How do I compare class types in C ++?
Let's say I have:
class Base {/*...*/}
class Derived1: public Base {/*...*/}
class Derived2: public Base {/*...*/}
.. and I have:
class SomeClass {
public:
template<typename DerivedType>
DerivedType GetDerived();
private:
vector<Base*> m_classes;
}
In the function, GetDerived()
I iterate over the vector m_classes and want to do something like:
if(m_classes[i] == DerivedType) {
return m_classes[i];
}
... and suppose we know that one of the objects in m_classes will contain a DerivedType object.
Example:
m_classes[2] = Base* BasePtr = new Derived1;
.. in this case I would like to use the GetDerived function like this:
GetDerived<Derived1>();
.. and this should return m_classes [2]
How should I do it? How do I compare a base pointer object with a derived class type? More precisely, what should the function look like GetDerived()
?
source to share
Storing objects of different classes in the same container when you need to treat them differently is a bad idea.
This time, C ++ has what you are looking for. dynamic_cast<B>(a)
will try to convert a
(whatever it is) for input B
. If the execution classes don't match, it will return nullptr
.
This is how you could write GetDerived
:
template <class Tsearched>
Tsearched *GetDerived() {
for(auto c : m_classes) {
if(Tsearched *ptr = dynamic_cast<Tsearched*>(c))
return ptr;
}
return nullptr;
}
Or, using the standard algorithm:
template <class Tsearched>
Tsearched *GetDerived() {
auto found = std::find_if(m_classes.begin(), m_classes.end(), [](Base *ptr) {
return dynamic_cast<Tsearched*>(ptr);
});
return found == m_classes.end() ? nullptr : static_cast<Tsearched*>(*found);
}
Let me repeat, however, that there is a design issue here. RTTI (what it uses dynamic_cast
) is neither elegant nor fast.
source to share
You can use dynamic_cast<>
:
template<typename DerivedType>
std::vector<DerivedType*> GetDerived() { // note: return type changed
std::vector<DerivedType*> result;
for (DerivedType* at : this->m_classes) {
if (DerivedType* as = dynamic_cast<DerivedType*>(at)) {
result.push_back(as);
}
}
return result;
}
dynamic_cast<>
a type Base
with runtime type information is required (which will exist for types that have virtual functions).
It's worth noting that some people don't like dynamic_cast<>
it and some conventions / codebases prohibit it. It is a tool and can be misused.
source to share
It's usually not good to do this kind of thing.
You can use dynamic_cast
which returns nullptr
if the object is not of this type and a pointer to that type otherwise:
if (nullptr != dynamic_cast<DerivedType*>(m_classes[i]))
{ ... }
source to share
As other people have said, you should see if this is indeed the best way to attack your problem, but dynamic_cast
available in C ++. You must use Runtime Type Identification or RTTI.
Once you've enabled it in your compiler options, you can do this in your loop:
DerivedType* maybeDerived = dynamic_cast<DerivedType>(m_classes[i]);
if (maybeDerived)
return maybeDerived;
source to share
Your example is not valid syntax. You have no announcement in the middle of the assignment. However, something like http://en.cppreference.com/w/cpp/types/is_base_of can help identify derivations at compile time. As far as defining derived types at runtime is concerned, you can use dynamic_cast
, however ideal solutions do not need to do this, and this often means that there is a potential design error in your objects or a way of using them.
As @PaulMcKenzie pointed out, you should probably be asking yourself, "Why?" before you worry about how.
source to share