【问题标题】:Storing classes inherited of a class template in a C++ Vector将类模板继承的类存储在 C++ 向量中
【发布时间】:2016-08-23 15:47:37
【问题描述】:

我想将派生自类模板MyClassTemplate 的类存储在向量中。

不幸的是,在 C++ 中,如果不指定其参数(类似于 std::vector<MyClassTemplate<?,?>> myVector;),就无法定义 MyClassTemplate 的向量。

但是有一种可能的解决方案是将非模板化接口(仅具有纯虚函数的类)定义为向量中项目的类型。 该接口由类模板继承。在我的例子中,类模板只有使用模板参数的成员,所以看起来只有一个空接口才是适合我的 Vector 的项目类型。

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

【问题讨论】:

  • std::vector<MyClassTemplate<?,?>> myVector; 不可能是什么意思?请举个小例子
  • @VittorioRomeo 我确定MyClassTemplate<A,B>MyClassTemplate<C,D> 在一个向量中。
  • 为什么要将不相关类型的元素存储在容器中?如果您不知道它们的类型,您将如何对它们进行任何操作?

标签: c++ templates inheritance vector interface


【解决方案1】:

我从你的问题中了解到:

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

如何解决?

首先,您可以定义一个通用的非模板祖先:

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&lt;MyCommonAncestor&gt;,因为这样的向量将只保存MyCommonAncestor 对象(无法创建,因为它们在这里有一个纯虚函数),如果他们可以被创建时,它们将slice 您放入的派生对象(即它们可能会丢失myXmyY)。

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

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

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

挑战

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

可能的解决方法:

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

Online demo (with smart pointers)

【讨论】:

  • @isanae 你完全正确!通常这就是我所做的,但我在这里省略了它,因为这个问题是相当概念性的。但我已经编辑了错别字并添加了一个在线演示的链接
【解决方案2】:

如果我理解正确,你想要这样的东西:

template <class T>
struct S { void f(); };

std::vector<S> v;

其中v 可以包含来自S&lt;&gt; 的任何实例化。你将无法做到。 S&lt;&gt; 是一个类模板。您可以将其视为一个类型生成器。您从 S&lt;&gt; 生成的每种类型都是不同的:S&lt;int&gt;S&lt;float&gt;intfloat 本身一样不同。

如果你想拥有任意S&lt;&gt;的容器,你需要打出多态卡:

struct base
{
    virtual ~base() = default;
    virtual void f() = 0;
};

template <class T>
struct S : base
{
    void f() override
    {
        std::cout << typeid(T).name() << "\n";
    }
};


int main()
{
    std::vector<std::unique_ptr<base>> v;
    v.push_back(std::make_unique<S<int>>());
    v.push_back(std::make_unique<S<float>>());
    v.push_back(std::make_unique<S<char>>());

    for (auto&& s : v)
        s->f();
}

输出:

int
float
char

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多