【问题标题】:overriding the template base method in derived class?覆盖派生类中的模板基方法?
【发布时间】:2017-04-29 23:04:57
【问题描述】:

假设我有一个基类如下:

template <typename T>
class Base {
    // implementation
    void do_something() { /* ... */ } ;
};

然后,我如下创建一个Derived 类,并覆盖do_something() 方法:

template <typename T>
class Derived : public Base<T> {
    // implementation
    void do_something() { /* ... */ } ;
};

我知道虚拟化在类模板中不起作用,我只是隐藏了方法的实现。但我确实想将一堆派生类和基类存储到一个向量中,(我不想使用类型擦除或多态),

我的问题是,鉴于Derived 类到基类的static_cast 给了我基类的do_something,有什么方法可以将它们存储为基类,而每个都有@987654328 的实现@类?

【问题讨论】:

    标签: c++ c++11 class-template


    【解决方案1】:

    我这样做了,它似乎工作正常:

    #include <iostream>
    
    template <typename T>
    struct Base {
        virtual void do_something() { std::cout << "Base::do_something()\n"; }
    };
    
    template <typename T>
    struct Derived : public Base<T> {
        virtual void do_something() { std::cout << "Derived::do_something()\n"; }
    };
    
    int main() {
        Base<int> b;
        Derived<int> d;
        Base<int> *p;
        p = &b;
        p->do_something();
        p = &d;
        p->do_something();
        return 0;
    }
    

    输出:

    Base::do_something()
    Derived::do_something()
    

    【讨论】:

      【解决方案2】:

      melpomene 答案的一些变化(为Base&lt;T&gt; 结构添加无模板基结构BaseOfBase)允许使用不同T 类型的派生类基的公共向量。

      一个工作示例

      #include <vector>
      #include <iostream>
      
      struct BaseOfBase
       { virtual void do_something () = 0; };
      
      template <typename T>
      struct Base : public BaseOfBase
       {
         T val;
      
         void do_something ()
          { std::cout << "Base::do_something() [" << val << "]\n"; };
       };
      
      template <typename T>
      struct Derived : public Base<T>
       { void do_something()
          { std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
      
      int main ()
       {
         std::vector<BaseOfBase*> vpbb;
      
         Base<int>            bi;
         Derived<int>         di;
         Base<std::string>    bs;
         Derived<std::string> ds;
      
         bi.val = 1;
         di.val = 2;
         bs.val = "foo";
         ds.val = "bar";
      
         vpbb.push_back(&bi);
         vpbb.push_back(&di);
         vpbb.push_back(&bs);
         vpbb.push_back(&ds);
      
         for ( auto const & pbb : vpbb )
            pbb->do_something();
       }
      

      【讨论】:

      • OP 说 - 我不想使用类型擦除,或多态。
      • @skypjack - 是的,但也说“我知道虚拟化在类模板中不起作用”
      • 很公平。 ;-)
      【解决方案3】:

      但我确实想将一堆派生类和基类存储到一个向量中,(我不想使用类型擦除或多态),

      这在 C++ 中已经不可能了。在 C++ 中,向量只能包含相同静态类型的对象。向量可以包含不同类型对象的唯一方法是它们的静态类型仍然相同,但它们具有不同的动态类型,但这是你说你不想使用的类型擦除/多态。

      我认为也许您需要重新考虑您的要求,因为您的问题本质上是:我想做某事,但我不想使用技术 X,它被明确定义为在 C++ 中做某事的唯一方法!

      【讨论】:

        【解决方案4】:

        当我们说虚拟化在模板类中不起作用时,我们并不是说你不能在模板类中执行虚函数,也不意味着你不能用它的专门版本覆盖成员函数.

        @melpomene 展示了一个一般覆盖的示例,我将在这里专门展示:

        #include <iostream>
        
        template <typename T>
        class Base {
            public:
                virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
        };
        
        
        class Derived : public Base<int> {
            public:
                virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
        };
        
        void main()
        {
            Base<int> b;
            Derived d;
            Base<int> *p = &b;
            auto r1 = p->do_something(10);
            std::cout << r1 <<std::endl;
            p = &d;
            auto r2 = p->do_something(10);
            std::cout << r2 << std::endl;        
        }
        

        哪个会输出

        Base::do_something()                                                                                                        
        10                                                                                                                          
        Derived::do_something()                                                                                                     
        9 
        

        显示它按预期完美运行。

        我们这么说是什么意思

        虚拟化在类模板中不起作用

        基本上意味着当需要基类时,您不能将派生类用作模板。

        考虑上面的类Base&lt;T&gt;和Derived,那么如果我们有以下代码:

        #include <memory>
        
        template <typename T>
        void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
        
        void main()
        {
            Base<int> b;
            Derived d; 
        
            auto ptr = std::unique_ptr<Derived>(&d);
            Test(ptr); // <-- Will fail to compile as an invalid argument
        }
        

        它将失败,因为std::unique_ptr&lt;Derived&gt; 不继承自 std::unique_ptr&lt;Base&lt;T&gt;&gt;,尽管 Derived 本身继承自 Base&lt;T&gt;。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-15
          • 2016-03-17
          • 1970-01-01
          • 2011-06-01
          • 2018-06-06
          • 1970-01-01
          • 2017-06-22
          • 1970-01-01
          相关资源
          最近更新 更多