2013-05-13 89 views
29

我需要在单个向量中存储多种类型的模板类。C++一个包含多种类型的模板类的std :: vector

例如,为:

template <typename T> 
class templateClass{ 
    bool someFunction(); 
}; 

我需要将存储所有的一个载体:

templateClass<int> t1; 
templateClass<char> t2; 
templateClass<std::string> t3; 
etc 

据我知道这是不可能的,如果是会有人说怎么样?

如果无法解释如何做出如下工作?

作为解决办法,我尝试使用基本非模板类,并从中继承模板类。

class templateInterface{ 
    virtual bool someFunction() = 0; 
}; 

template <typename T> 
class templateClass : public templateInterface{ 
    bool someFunction(); 
}; 

我然后创建了一个矢量来存储基地“templateInterface”级:

std::vector<templateInterface> v; 
templateClass<int> t; 
v.push_back(t); 

这将产生以下错误:

error: cannot allocate an object of abstract type 'templateInterface' 
note: because the following virtual functions are pure within 'templateInterface' 
note: virtual bool templateInterface::someFunction() 

为了解决这个错误我在取得的功能templateInterface不是通过提供一个函数体来进行纯虚拟,而是在编译时调用该函数而不是使用overide而是在虚函数中使用body。

如:

class templateInterface{ 
    virtual bool someFunction() {return true;} 
}; 

template <typename T> 
class templateClass : public templateInterface{ 
    bool someFunction() {return false;} 
}; 

std::vector<templateInterface> v; 
templateClass<int> i; 
v.push_back(i); 
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body 

有什么办法来解决这个问题,这样的重写功能被使用,或者是有其他的解决方法来存储多种模板类型中的一个载体?

+0

看看这个链接http:// stackoverflow。com/questions/5627215/how-to-make-a-vector-of-template-structs – Elior 2013-05-13 17:25:11

回答

24

为什么您的代码不起作用:

调用虚函数不使用多态。它调用为编译器所看到的确切符号类型定义的函数,而不是运行时类型。当你将子类型插入到基类型的向量中时,你的值将被转换成为基类型(“类型切片”),这不是你想要的。对它们调用函数现在将调用为基类型定义的函数,因为不是是该类型的

如何解决这个问题?

同样的问题可以与此代码段被再现:

templateInterface x = templateClass<int>(); // Type slicing takes place! 
x.someFunction(); // -> templateInterface::someFunction() is called! 

多态性仅适用于一个指针参考类型。然后它将使用指针/引用背后的对象的运行时类型来决定调用哪个实现(通过使用它的vtable)。

转换指针对于类型切片是完全“安全的”。您的实际的值根本不会被转换,多态性将按预期工作。

实施例,类似于上面的代码段:

templateInterface *x = new templateClass<int>(); // No type slicing takes place 
x->someFunction(); // -> templateClass<int>::someFunction() is called! 

delete x; // Don't forget to destroy your objects. 

什么矢量?

所以你必须在你的代码中采用这些改变。您只需将指针存储到向量中的实际类型,而不是直接存储值。

使用指针时,你也必须关心删除你分配的对象。为此,您可以使用智能指针,该指针自动关心删除。 unique_ptr就是这样一种智能指针类型。只要它超出范围(“唯一所有权” - 作为所有者的范围),就会删除指针。假设你的对象的生命周期是绑定到这个范围,你应该使用什么:

std::vector<std::unique_ptr<templateInterface>> v; 

templateClass<int> *i = new templateClass<int>(); // create new object 
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector 

v.emplace_back(new templateClass<int>()); // "direct" alternative 

然后,调用虚函数的语法如下这些元素之一:

v[0]->someFunction(); 

确保您将使所有功能虚拟应该可能被子类覆盖。否则,他们的重写版本将不会被调用。但既然你已经引入了一个“接口”,我相信你正在使用抽象函数。

替代方法:

其它方法来完成你想要的是在矢量使用变种类型。有一些变体类型的实现,Boost.Variant是非常流行的。如果您没有类型层次结构(例如,当您存储基元类型时),此方法尤其好。然后你会使用一个向量类型,如std::vector<boost::variant<int, char, bool>>

+0

智能指针_may_是正确的解决方案,但在他的示例代码中,他没有动态分配对象。如果它们是具有静态生命周期的对象,则不需要在它们上使用智能指针,只需要获取它们的地址。如果他确实需要一份副本(因为初始化对象的寿命不足),那么你可能应该这样说。 – 2013-05-13 17:31:13

+0

'v.emplace_back(new templateClass ();' – 2013-05-13 17:31:18

+0

@JamesKanze:在他的原始代码中,载体包含了当地人的副本,除非他另有说明,否则我猜测载体需要保留副本,需要对多态性进行动态分配 – 2013-05-13 17:32:23

2

多态只能通过指针或引用。你需要 需要非模板库。除此之外,您需要决定容器中的实际对象将在哪里生存的 。如果他们都是 静态物体(具有足够的使用寿命),只需使用 a std::vector<TemplateInterface*>,并插入 v.push_back(&t1);等应该做的伎俩。否则, 您可能会想要支持克隆,并将克隆保存在 向量中:最好使用Boost指针容器,但也可以使用 std::shared_ptr

1

如果你正在寻找一个容器来存储多种类型,那么你应该从流行的boost库中探索boost variant

2

到目前为止给出的解决方案都很好,但请注意,如果您在示例中返回除bool之外的模板类型,则这些都不会有帮助,因为vtable插槽无法在手动测量之前进行测量。从设计角度来看,实际上有限制使用面向模板的多态解决方案。

相关问题