I'm working with a class library where all classes are, directly or indirectly, derived from a base class Base
and have a name. The library provides a facility to search for objects by a name, which will return a Base*
.
Is there any way to find the type of the returned object without checking all possibilities using dynamic_cast
s as I did in the following example? I'd like to avoid that, if at all possible, since the derived classes have template parameters, which makes for quite a few possibilities.
It would also be fine if I were at least able to find out the class type (T1
or T2
, in the example below) without knowing the template type, ie. do something like a dynamic_cast<T1<i_dont_care>*>
.
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
};
template <typename T> class T1 : public Base {};
template <typename T> class T2 : public Base {};
Base *find_by_name() {
return new T2<int>();
}
int main() {
Base *b = find_by_name();
if (T1<int> *p = dynamic_cast<T1<int>*>(b)) {
cout << "T1<int>" << endl;
// do something meaningful with p
} else if (T1<double> *p = dynamic_cast<T1<double>*>(b))
cout << "T1<double>" << endl;
else if (T2<int> *p = dynamic_cast<T2<int>*>(b))
cout << "T2<int>" << endl;
else if (T2<double> *p = dynamic_cast<T2<double>*>(b))
cout << "T2<double>" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}
Note that the above example is simplified, ie. in each if
I'd do something meaningful with p
.
I do realize that this is bad design from the very start, however I'm stuck with this library and there's also no way for me to change its implementation.
Derived class pointer cannot point to base class.
Explanation: A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer because object slicing happens when a derived class object is assigned to a base class object.
C++ has no direct method to check one object is an instance of some class type or not. In Java, we can get this kind of facility. In C++11, we can find one item called is_base_of<Base, T>. This will check if the given class is a base of the given object or not.
A derived class is a class which takes some properties from its base class. It is true that a pointer of one class can point to other class, but classes must be a base and derived class, then it is possible.
At runtime, you need to interrogate dynamically the type of particular class. Use runtime type identification (commonly referred to as RTTI) to query the address of the object for the type of object it points to. Example 8-6 shows how. Example 8-6. Using runtime type identification
In this tutorial, we will discuss the concept of the base class pointer in C++ and its implementation in the program. What is a pointer? A pointer is a type of variable or a memory location that contain the address of other variables or object.
A pointer to derived class is a pointer of base class pointing to derived class, but it will hold its aspect. This pointer of base class will be able to temper functions and variables of its own class and can still point to derived class object. Writing code in comment?
To access the variable of the base class, base class pointer will be used. So, a pointer is type of base class, and it can access all, public function and variables of base class since pointer is of base class, this is known as binding pointer. In this pointer base class is owned by base class but points to derived class object.
There's something like typeid
http://en.cppreference.com/w/cpp/language/typeid, which applied to polymorphic expression will evaluate in a runtime to its type representation.
Following wiki example: https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast
#include <iostream>
#include <typeinfo> // for 'typeid'
class Person {
public:
virtual ~Person() {}
};
class Employee : public Person {
};
int main()
{
Person person;
Employee employee;
Person* ptr = &employee;
Person& ref = employee;
// The string returned by typeid::name is implementation-defined
// Person (statically known at compile-time)
std::cout << typeid(person).name() << std::endl;
// Employee (statically known at compile-time)
std::cout << typeid(employee).name() << std::endl;
// Person* (statically known at compile-time)
std::cout << typeid(ptr).name() << std::endl;
/* Employee (looked up dynamically at run-time
* because it is the dereference of a
* pointer to a polymorphic class) */
std::cout << typeid(*ptr).name() << std::endl;
// Employee (references can also be polymorphic)
std::cout << typeid(ref).name() << std::endl;
}
There is a typeid
operator, which returns an instance of std::type_info
, with which you can get the name of the type.
Not sure if that will help you though. First, the returned name is not guaranteed to be the same across implementations. Second - what would you do once you have the name? You'd compare it with your pre-defined names probably, but that is probably slower than a bunch of dynamic_cast
's.
Without type support built into your Base
class or a new intermediate layer of hierarchy, dynamic_cast
is your best choice. In reality it will be very fast (usually just a single compare instruction).
By intermediate layer I mean:
class Base {
public:
virtual ~Base() {}
};
class T1Base : public Base {};
class T2Base : public Base {};
template <typename T> class T1 : public T1Base {};
template <typename T> class T2 : public T2Base {};
int main() {
Base *b = find_by_name();
if (dynamic_cast<T1Base*>(b))
cout << "T1" << endl;
else if (dynamic_cast<T2Base*>(b))
cout << "T2" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With