c++ - 在 C++ Vector 中存储从类模板继承的类

标签 c++ templates inheritance vector interface

我想存储派生自类模板的类 MyClassTemplate在一个 vector 中。

不幸的是,在 C++ 中无法定义 MyClassTemplate 的 vector 。没有指定它的参数(类似于 std::vector<MyClassTemplate<?,?>> myVector; )。

但是有一个可能的解决方案,即定义一个非模板化接口(interface)(只有纯虚函数的类)作为 vector 中项目的类型。 该接口(interface)由类模板继承。在我的例子中,类模板只有使用模板参数的成员,所以似乎只有一个空接口(interface)才是适合我的 Vector 的项目类型。

这个问题还有其他(更好的)解决方案吗?

最佳答案

我从你的问题中了解到:

  • 你有一个模板类MyClassTemplate<class X, class Y> ;
  • 您已经知道每个模板实例化(例如 MyClassTemplate<A,B>MyClassTemplate<U,V> )都是不同的不相关类型;
  • 尽管如此,您还是希望将这种不相关的类型放在同一个 vector 中,以便能够使用公共(public)接口(interface)并以多态方式使用 vector 元素。

如何解决?

首先,您可以定义一个公共(public)的非模板祖先:

class MyCommonAncestor {
public:  
    virtual void common_operation1()=0;
    virtual ~MyCommonAncestor() {}
}; 

template <class X, class Y> 
class MyTemplateClass : public MyCommonAncestor {
    X myx; 
    Y myY; 
public:  
    void common_operation1() override; 
    X operation2(const Y& y); 
};

不幸的是,这样做并不能真正让您使用 vector<MyCommonAncestor>因为这样的 vector 会持有 MyCommonAncestor只有对象(不能创建,因为它们在这里有一个纯虚函数),如果可以创建,它们将 slice您放入的派生对象(即它们有丢失 myXmyY 的风险)。

但是您可以创建一个指针 vector 。我在这里展示了一个简化的示例,使用原始指针;但实际上你最好使用 shared_ptr :

vector<MyCommonAncestor*> myVector; 
myVector.push_back(new MyTemplateClass<A,B>); 
myVector.push_back(new MyTemplateClass<U,V>); 

然后您可以根据 MyCommonAncestor 遍历元素并应用常用函数的界面。

挑战

当您要调用依赖于模板参数的函数时会遇到挑战(例如 operation2() )。显然,这些不能包含在共同祖先中,因为它们依赖于尚未定义的模板参数。

可能的解决方法:

  • 避免这些,并且仅通过通用操作(可以在模板中覆盖)间接调用此类函数
  • 在通用接口(interface)中使用参数抽象类型。通过指针或引用传递这些。稍后,对于 A 和 B 或 U 和 V,确保它们是从预期的抽象类型派生的。

Online demo (with smart pointers)

关于c++ - 在 C++ Vector 中存储从类模板继承的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39105623/

相关文章:

java - Hibernate合并丢失数据

c++ - 澄清 Sean Parent 的谈话 "Inheritance is the base class of evil"

c++ - 标准库中的 Visual Studio 编译错误

c++ - C++0x 正式发布了吗?主要编译器支持吗?

c++ - 为什么类模板的成员函数声明都应该是良构的?

python - Debian 上的 Django 管理目录

c++ - 嵌套模板歧义

javascript - 扩展原型(prototype)、继承和 super

c++ - g++ lambda declared using local type ... 已使用但从未定义 - 真的是错误吗?

c++ - 真的对 map::erase() 感到困惑