重写派生类中的模板基方法?

overriding the template base method in derived class?

本文关键字:方法 派生 重写      更新时间:2023-10-16

>假设我有一个基类,如下所示:

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,有什么方法可以将它们存储为基类,而每个类都有do_something()类的实现?

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

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

我认为也许你需要重新考虑你的要求,因为你的问题本质上是:我想做某事,但我不想使用技术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();
}

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

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