c ++对象工厂函数

时间:2013-02-18 22:37:55

标签: c++ factory object-slicing

假设我有以下数据结构:

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;
}

除了模板方法之外还有更好的解决方案吗?

2 个答案:

答案 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,而是将不同派生实例的所有内容写为虚拟成员函数。