Reputation: 257
Lets say I've got:
class Base {/*...*/}
class Derived1: public Base {/*...*/}
class Derived2: public Base {/*...*/}
..and I've got:
class SomeClass {
public:
template<typename DerivedType>
DerivedType GetDerived();
private:
vector<Base*> m_classes;
}
In the GetDerived()
function I iterate trough the m_classes vector and I would like to do something like:
if(m_classes[i] == DerivedType) {
return m_classes[i];
}
...and lets assume we know that one of the objects in the m_classes will contain a 'DerivedType' object.
Example:
m_classes[2] = Base* BasePtr = new Derived1;
.. in this case I'd like to use the GetDerived function like this:
GetDerived<Derived1>();
.. and this should return m_classes[2]
How do I do this? How do I compare a base pointer object with a derived class type? More exactly, how should the GetDerived()
function look like?
Upvotes: 5
Views: 13206
Reputation: 1338
As other people have said, you should see if this is really the best way to attack your problem, but dynamic_cast
is available in C++. You have to use Run Time Type Identification or RTTI.
Once you've turned it on in your compiler options you can do this inside your loop:
DerivedType* maybeDerived = dynamic_cast<DerivedType>(m_classes[i]);
if (maybeDerived)
return maybeDerived;
Upvotes: 1
Reputation: 63124
Storing objects of different classes in the same container when you need to treat them differently is a bad idea.
C++ however has what you're looking for, this time. dynamic_cast<B>(a)
will try and convert a
(whatever it is) to type B
. If the runtime classes do not match, it will return nullptr
.
Here 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, with the help of a 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 in here. RTTI (what dynamic_cast
uses) is neither elegant, nor fast.
Upvotes: 3
Reputation: 104698
You could 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<>
requires a Base
type with Run Time Type Information (which will exist on types which have virtual functions).
It's worth mentioning that some people dislike dynamic_cast<>
, and some conventions/codebases forbid it. It's a tool, and it can be misused.
Upvotes: 2
Reputation: 3778
Usually it's not a good idea to do things like that.
You can use dynamic_cast
which returns nullptr
if the object is not of that type and a pointer to that type otherwise :
if (nullptr != dynamic_cast<DerivedType*>(m_classes[i]))
{ ... }
Upvotes: 1
Reputation: 16197
Your example is not valid syntax. You can't have a declaration in the middle of an assignment. However something like http://en.cppreference.com/w/cpp/types/is_base_of can help identify derivations at compile time. As far as identifying derived types at runtime you can use dynamic_cast
however ideal solutions should not need to do this and it often means there is a potential design flaw in your objects or the way they are being used.
As pointed out by @PaulMcKenzie you should probably be asking yourself "Why?" before worrying about the how.
Upvotes: 0