2

Suppose I have a base class as below:

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

then, I create a Derived class as below, and override the do_something() method:

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

I know virtualization does not work in class templates, and I am just hiding the implementation of the methods. 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),

my question is, given that static_cast of Derived class to base class gives me the do_something of based class, Is there any way that I can store them as base classes while each has their implementation of do_something() class ?

4

4 回答 4

3

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

#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()
于 2017-04-29T23:16:42.217 回答
2

melpomene 的答案稍有变化(为结构添加无模板基结构 , BaseOfBase)允许使用不同类型Base<T>的派生类的通用基向量。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();
 }
于 2017-04-30T00:29:56.420 回答
2

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

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

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

于 2017-04-29T23:16:15.713 回答
0

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

@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<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>.

于 2020-06-04T23:31:44.287 回答