首页 文章

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

提问于
浏览
7

我有以下层次结构:

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

现在给出一个指向base的指针,我想知道底层是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";

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

4 回答

  • 3

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

    代替:

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

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

    NOTE :我考虑 dynamic_cast<> a code smell 的清单,我建议你重新考虑一下你的方法 .

  • 9

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

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

    解决方案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;
    }
    

相关问题