2012-08-28 78 views
0

我有一个基部结构FooBaseC++存储模板结构

struct FooBase { }; 

然后,我创建的模板结构Foo其为FooBase子:

template <typename typeName> struct Foo : public FooBase { typeName* foo }; 

在一些I类创建的矢量FooBase并在其中添加Foo的实例:

vector <FooBase> FooVector 
...  
Foo <Bar> fooInstance; 
fooInstance.foo = new Bar(); 
FooVector.push_back (fooInstance); 

然后我需要访问存储的数据,但我发现了可预见的和明显的错误有关的缺席成员fooFooBase

FooVector[0].foo 

我不能写类似

Foo <Bar> fooInstance = FooVector[0] 

因为我不知道模板参数。

如何将Foo的实例存储在向量中,以便稍后可以访问它们。 请注意,在最后一步 - 从矢量读取数据时,我不知道模板参数。

P.S.不允许增强!

+0

你可以用'typename'来引用'Bar'吗?你需要用'Bar'来做任何特定于它的类型(我的猜测是否定的)。 – MartyE

+1

你正在寻找的是一种称为类型擦除的技术。 – Ylisar

回答

2

这里会发生什么事,是在你的

FooVector.push_back (fooInstance); 

线,C++默默调用的FooBase拷贝构造函数,因为你只能保持这种类型的对象在您的载体。由于FooFooBase公开继承,所以方法FooBase::FooBase(FooBase const&)可以用Foo类型的对象调用

所以,你不是真的存储Foo s,但实际上FooBase s。要做你想做的事情,你需要一个std::vector<FooBase*>std::vector<std::shared_ptr<FooBase> >

然而,你的向量的内容,将仍然缺乏foo成员,因为静态类型仍然不Foo。为了解决这个问题,你有一些选择。您可能dynamic_caststatic_cast您的FooBase*转换为Foo*,然后访问其foo成员。但是这可能会中断,因为FooBase*指针可能实际上保存的类型不是Foo

为什么不直接使用std::vector<Foo<Bar> >呢?

+0

'为什么不使用std :: vector >?因为我不知道模板参数!酒吧只是一个例子。 – Kolyunya

+1

@Kolyunya:那你怎么能期待'.foo'给你正确的类型? – bitmask

+0

这是我的问题。如何使用我不知道的模板参数存储模板结构的向量。 – Kolyunya

1

您在这里切片:

vector <FooBase> FooVector 
...  
Foo <Bar> fooInstance; 
fooInstance.foo = new Bar(); 
FooVector.push_back (fooInstance); 

你推Foo<Bar>FooBase一个矢量,所以你只能获得存储在FooBase对象。这

FooVector[0] 

返回到FooBase其中一无所知Foo<Bar>参考。您可以直接存储Foo<Bar>

vector<Foo<Bar>> FooVector; 

或存储指针或智能指针FooBase,但随后你将不得不dynamic_cast的元素来Foo<Bar>*无论如何,这不是一个很好的解决方案。

+0

是的,我知道。我如何存储'Foo'的矢量?如果我将指针指向Foo指向FooBase指针,它会改变什么吗? – Kolyunya

+0

@Kolyunya:指针向量是避免切片的一种方法。但是,它会使向量的拷贝构造函数和拷贝分配做错误的事情。这是最丑陋的C++问题之一,海事组织。 (其他丑陋的解决方案包括ptr_vector,boost :: any,以及智能指针向量。) –

+0

@Kolyunya我在回答中添加了一些选项。 – juanchopanza

0

正如前面的答案中所提到的,您正在将Bar切片为FooBase对象。你的向量必须存储对Foo对象的引用,而不是对象本身。

完成此操作的最简单方法是使用boost库中的一个smart_ptr类型。

#include <boost/shared_ptr.hpp> 
#include <vector> 
typedef std::vector< boost::shared_ptr<FooBase> > FooVector; 
... 
FooVector v; 
v.push_back(new Bar()); 

如果指针本身存储到载体中你必须与内存管理的问题,使用升压shared_ptr的类型将自动处理分配给你的。

+0

(当然,您也可以为任何其他库使用智能指针类型或编写自己的,因为你不想使用Boost。关键是你需要的语义,而不是实现。) –

+0

正如David所说,你不必使用boost;然而,你应该使用某种智能指针实现为你的向量引用。而且你必须在向量中使用引用类型来避免切片问题。不使用智能指针会给您处理重新分配造成负担;这使得使用一些矢量方法(即擦除)非常危险。 –