2013-02-18 135 views
0

可以说我有以下的数据结构:C++对象工厂函数

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,名称和类别的载体的单个工厂方法在函数中是已知的。我遇到的问题是切片...

std::vector< Base* > getVector(...) 

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

难道还有比模板以外的任何更好的解决方案方法?

+1

你的'std :: vector getVector(...)'如何展示切片?你的成员会有不同的派生类型吗? – 2013-02-18 22:39:06

+0

您对问题的描述(“我遇到的问题是切片”)不完整。请发布一个**短**,**完整**程序来展示您的问题。请参阅http://sscce.org/。 – 2013-02-18 22:44:32

+0

“Base *”与“A *”大小相​​同。指针不会被切分。 – 2013-02-18 22:48:51

回答

1

你问的似乎值得商榷,因为你想:

  • 抽象对象的创建,直到运行时
  • 在编译时访问对象的创建后的特定成员

因此,有没办法让它工作得体。你的模板代码仍然需要在调用者站点静态地知道你的对象的类型,所以创建对象不会被抽象出来。

我的建议是再次考虑你的问题:你为什么想要一个动态工厂?为什么不能在Base类中共享访问器?

如果你不能清楚地回答这两个问题,这可能意味着你不应该有这个类的层次结构。

+0

事实证明,我只是让我的设计完全错误,请参阅对我的问题的回应。 – rem45acp 2013-02-18 23:09:30

+0

这就是我的意思是“可疑”:)很高兴听到你说得对。 – Mic 2013-02-18 23:11:48

1

我其实认为你的模板可能是最好的解决方案,至少它是惯用的C++。

使用RTTI(如dynamic_cast)也可以,但它不太安全(运行时与编译时类型检查)并且效率通常较低。然而,有时 - 或者经常在的事实 - 你需要有多态性在运行时决定只(例如,当你在同std::vector需要不同的派生的对象而不能使用固定长度std::tuple)。然后,您可以像您已经准备好的那样,通过使用基类指针而不是对象的矢量来解决切片问题。与(普通)指针的问题是,他们多少有些回避C++的自动内存管理:当std::vector<Base*>超出范围,所指向的派生的对象是按逗留闲逛的地方人迹罕至删除:你有内存泄漏。这就是为什么像Java这样的语言更多依赖于这种继承方式的垃圾收集。 This problem is discussed elsewhere,推荐的解决方案是用std::unique_ptr<Base>代替Base*

一旦你有了这个运行,那么你可以利用运行时多态性的功能。你通常需要dynamic_cast,而是应该写到哪不同来源的情况下,不同的虚成员函数的一切。