从基指针向下转换到模板化派生类型

Downcasting from base pointer to templated derived types

本文关键字:派生 类型 转换 指针      更新时间:2023-10-16

我有以下层次结构:

class base
{
public:
   virtual ~base(){}
   virtual void foo() {}
};
template <typename T>
class derived1 : public base
{
   virtual void foo() {};
};
template <typename T>
class derived2 : public base
{
   virtual void foo() {};
};

现在给一个指向基地的指针,我想知道底层是derived1或derived2。问题是derived1和derived2可以专门用于许多不同的类型,使用dynamic_cast测试向下转换需要要知道的模板类型。我最终得到了混乱、无法维护和不完整的代码:

base* b = new derived1<int>();
if (dynamic_cast<derived1<int>*> ||
    dynamic_cast<derived1<unsigned int>*> ||
    dynamic_cast<derived1<double>*>)
  std::cout << "is derived1";
else if (dynamic_cast<derived2<int>*> ||
    dynamic_cast<derived2<unsigned int>*> ||
    dynamic_cast<derived2<double>*>)
  std::cout << "is derived2";

有没有更好的方法,可以处理任何类型的专业化?

将依赖于类型的逻辑移动到类型中。

代替:

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";

virtual print_name() const函数添加到base,然后执行:

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";
   }
};

basederived1derived2:之间插入一个非模板类

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() {}
};

在一条评论中,你提到:

[我想]为每个函数调用一个特定的函数-顺便说一句derived1和derived2

将该(虚拟)函数添加到derived1_base中,您甚至不需要再了解T

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();
}

注意:我认为dynamic_cast<>是一个代码气味的列表,我敦促您重新思考您的方法。

您可以添加一个虚拟方法来进行某种类型的元类型检查:

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;}
};

解决方案1:再添加一个虚拟函数:

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; }
}; 

解决方案2:使用标签类:

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;
}