覆盖派生 class 中的模板基方法?

overriding the template base method in derived class?

假设我有一个基 class 如下:

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

然后,我创建一个 Derived class 如下,并重写 do_something() 方法:

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

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

我的问题是,假设 static_cast of Derived class to base class 给我 do_something of based class,有什么方法可以将它们存储为基础 classes 而每个都有 do_something() class 的实现?

but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),

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

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

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

#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()

melpomene 的答案有一点变化(为 Base<T> 结构添加一个无模板基结构,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();
 }

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

@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 

表明它完全按预期工作。

我们说

的意思

virtualization does not work in class templates

基本上意味着您不能将派生的 class 用作模板,而该基数是预期的。

考虑上面的classes Base<T>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<Derived> 没有继承自 std::unique_ptr<Base<T>>,尽管 Derived 本身继承自 Base<T>