假设我有以下数据结构:
struct Base
{
Base(const int id, const std::string &name, const std::string &category):
id(id), name(name), category(category) {}
int id;
std::string name;
std::string category;
};
struct A : public Base
{
A(const int id, const std::string &name, const std::string &category,
const int x, const int y) :
Base(id, name, category), x(x), y(y) {}
int x, y;
};
我想创建一个单个工厂方法,该方法返回派生类的向量,其中id,name和category在函数中是已知的。我遇到的问题是切片......
std::vector< Base* > getVector(...)
结构A的数据成员丢失了! (dynamic_cast回到生产代码中可接受的A?)
所以我有这个模板方法,但我仍然不认为它是最好的解决方案:
template< class T >
std::vector< T > getVector()
{
std::vector< T > retVal;
retVal.push_back(T(45, "The Matrix", "Science Fiction"));
retVal.push_back(T(45, "Good Luck Chuck", "Comedy"));
...
return retVal;
}
除了模板方法之外还有更好的解决方案吗?
答案 0 :(得分:1)
你要求的东西似乎有问题,因为你想要:
所以没有办法让它运作得体。您的模板代码仍然需要静态地知道调用者站点上对象的类型,因此不会抽象出对象创建。
我的建议是再考虑一下你的问题:为什么你想拥有一个充满活力的工厂?为什么不能在Base
类中共享所有对象的访问者?
如果你不能清楚地回答这两个问题,那么可能意味着你不应该首先拥有这个类层次结构。
答案 1 :(得分:1)
我实际上认为你的模板可能是最好的解决方案,至少它是惯用的C ++。
使用诸如dynamic_cast
之类的RTTI也没问题,但它的安全性较低(运行时与编译时类型检查)并且效率通常较低。但是,有时 - 或者经常是 - 实际上 - 需要才能在运行时决定多态性(例如,当您需要在同一std::vector
中使用不同的派生对象时,不能使用固定的-length std::tuple
)。然后,您可以像已经准备好的那样,通过使用基类指针的向量而不是对象来解决切片问题。 (普通)指针的问题在于它们有点绕过C ++的自动内存管理:当std::vector<Base*>
超出范围时,指向的派生对象不被删除某处无法访问:您有内存泄漏。这就是为什么像Java这样依赖于这种使用继承方式的语言被垃圾收集的原因。 This problem is discussed elsewhere,建议的解决方案是将Base*
替换为std::unique_ptr<Base>
。
运行后,您可以使用运行时多态函数。您通常不需要dynamic_cast
,而是将不同派生实例的所有内容写为虚拟成员函数。