I have the following hierarchy:
class base
{
public:
virtual ~base(){}
virtual void foo() {}
};
template
class derived1 : public base
{
Solution 1: add one more virtual function:
enum DerivedType
{
One,
Two,
...
};
class base
{
public:
~base(){}
virtual void foo() {}
virtual DerivedType GetType() = 0;
};
template <typename T>
class derived1 : public base
{
virtual void foo() {};
virtual DerivedType GetType() { return One; }
};
template <typename T>
class derived2 : public base
{
virtual void foo() {};
virtual DerivedType GetType() { return Two; }
};
Solution 2: using tag classes:
class Base
{
public:
virtual ~Base() { }
};
class Derived1Tag
{ };
class Derived2Tag
{ };
template <class T>
class Derived1 : public Base, public Derived1Tag
{ };
template <class T>
class Derived2 : public Base, public Derived2Tag
{ };
int main(int argc, char** argv)
{
Derived1<int> d1;
Derived2<int> d2;
cout << dynamic_cast<Derived1Tag*>((Base*)&d1) << endl;
cout << dynamic_cast<Derived1Tag*>((Base*)&d2) << endl;
return 0;
}
Move the logic which depends on the type into the type.
Instead of:
if (dynamic_cast<derived1<int>*>(b) ||
dynamic_cast<derived1<unsigned int>*>(b) ||
dynamic_cast<derived1<double>*>(b))
std::cout << "is derived1";
else if (dynamic_cast<derived2<int>*>(b) ||
dynamic_cast<derived2<unsigned int>*>(b) ||
dynamic_cast<derived2<double>*>(b))
std::cout << "is derived2";
add a virtual print_name() const
function to base
, and then do:
void example() {
std::unique_ptr<base> b(new derived1<int>());
b->print_name();
}
class base
{
public:
~base(){}
virtual void foo() {}
virtual void print_name() const = 0;
};
template <typename T>
class derived1 : public base
{
virtual void foo() {}
virtual void print_name() const {
std::cout << "is derived1";
}
};
template <typename T>
class derived2 : public base
{
virtual void foo() {}
virtual void print_name() const {
std::cout << "is derived2";
}
};
Insert a non-templated class inbetween base
and derived1
or derived2
:
class base
{
public:
virtual ~base() {} // **NOTE** Should be virtual
virtual void foo() {}
};
class derived1_base : public base
{
};
template <typename T>
class derived1 : public derived1_base
{
public:
virtual void foo() {}
};
class derived2_base : public base
{
};
template <typename T>
class derived2 : public derived2_base
{
public:
virtual void foo() {}
};
In a comment, you mentioned:
[I want to] call a particular function for each one - btw there's more than derived1 and derived2
Add that (virtual) function to derived1_base
, and you don't even need to know T
anymore.
if (dynamic_cast<derived1_base*>(foo))
{
std::cout << "is derived1";
dynamic_cast<derived1_base*>(foo)->specific_derived1_function();
}
else if (dynamic_cast<derived2_base*>(foo))
{
std::cout << "is derived2";
dynamic_cast<derived2_base*>(foo)->specific_derived2_function();
}
NOTE: I consider a list of dynamic_cast<>
a code smell, and I urge you to rethink your approach.
You could add a virtual method to do a meta-type check of some kind:
class base
{
public:
~base(){}
virtual void foo() {}
virtual bool isa(const char* type_to_test){
return strcmp(type_to_test,"base")==0;}
};
template <typename T>
class derived1 : public base
{
virtual void foo() {};
virtual bool isa(const char* type_to_test){
return strcmp(type_to_test,"derived1")==0;}
};