为了重构一些基础结构代码,我决定使用继承来实现几个类之间的多态行为。下一步是将它们放入容器中,遍历它们并执行DoSomething();。

我当前的容器构造很笨拙。即使我将elegant解决方案用于容器,构造仍然是一团糟。

vector<unique_ptr<Parent>> vec;

vec.push_back(unique_ptr<Parent>(new ChildA(var1, var2)));
vec.push_back(unique_ptr<Parent>(new ChildB(var3, var4)));
vec.push_back(unique_ptr<Parent>(new ChildC(var5, var6)));

ChildA,ChildB和ChildC彼此都是多态的。
Var1 ... var6可能来自不同类型,并且是构造子对象所必需的。

我想在多个地方创建此 vector 以供使用。问题在于 child 的数量可能会有所不同,因此 child 需要构造数据。尝试走stdarg.h的路径失败,因为不支持此操作:
if     !defined(_WIN32)
#error ERROR: Only Win32 target supported!
#endif

您将如何实现构造此数组的工厂方法?

更新,所需的解决方案:
vec = CreatePolyVec(var1, var2, typeInfo1, var3, var4, typeInfo2, var5, var6 typeInfo3);
vec = CreatePolyVec(var1, var2, typeInfo1, var3, var4, typeInfo2);

第1行将创建与上述相同的数组。
第2行将重复使用相同的代码来创建相似的 vector ,但对象少一个。
Typeinfo包含创建对象所需的信息。

这是一种基本解决方案,更高级的解决方案将在编译时强制执行参数列表。例如,以下对函数的调用没有意义:
vec = CreatePolyVec(var1, var2,typeinfo1, var3, var4, typeinfo2, var5);

没有足够的参数来创建最后一个子对象。

最佳答案

这里有两个问题:1.如何确定每个 child 的类型,以及2.如何创建多个 child 。

决定要创建哪个 child

这可以在编译时或运行时完成。要在编译时执行此操作,您需要模板。

template<class Child, class Arg1, class Arg2>
vector<unique_ptr<Parent>> CreateVec(Arg1&& arg1, Arg2&& arg2)
{
    vector<unique_ptr<Parent>> result;
    result.push_back(unique_ptr<Child>(
        new Child(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))));
    return result;
}

称为CreateVec<MyChild>(myArg1, myArg2)

如果需要在运行时进行决策,则可以使用由运行时变量索引的工厂功能映射。或者,您可以使用指向工厂对象的指针作为运行时变量。

创造多个 child

在这里,您可以在链接函数和可变参数模板之间进行选择。

链式功能

本质上,这就是iostreams所做的。让您的函数创建一个 vector 并添加一个子代,然后返回一个对象,该对象使您可以添加第二个子代,并返回自身以允许您继续。

这里的问题是您希望函数返回 vector ,因此它也不能返回另一个对象。您可以使用转换运算符来获取 vector 或显式函数,但最简单的方法可能是首先创建 vector ,然后仅使用函数添加子代即可。
class AddChildren
{
    vector<unique_ptr<Parent>>& m_vector;
public:
    explicit AddChildren(vector<unique_ptr<Parent>>& theVector)
        : m_vector(theVector) {}

    template<class Child, class Arg1, class Arg2>
    AddChildren& add(Arg1&& arg1, Arg2&& arg2)
    {
        m_vector.push_back(unique_ptr<Child>(
            new Child(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))));
        return *this;
    }
};

用法如下:
vector<unique_ptr<Parent>> myvector;
AddChildren(myvector)
    .add<ChildA>(var1, var2)
    .add<ChildB>(var3, var4)
    .add<ChildC>(var5, var6);

如果使用的是运行时选择类型的方法,则可以使用operator()并使它看起来像这样:
vector<unique_ptr<Parent>> myvector;
AddChildren(myvector)
    (childAType, var1, var2)(childBType, var3, var4)(childCType, var5, var6);

(这也可以通过为每个子类型使用特定类型选择器类型的伪对象作为参数,在类型的编译时选择来完成。)

使用可变参数模板

使用可变参数模板一次剥离三个参数,并添加一个子对象。
void addChildren(vector<unique_ptr<Parent>>& theVector)
{}

template<class FirstChild, class FirstArg1, class FirstArg2, class... Rest>
void addChildren(vector<unique_ptr<Parent>>& theVector,
    FirstChild childtype, FirstArg1&& arg1, FirstArg2&& arg2, Rest&&... rest)
{
    addChild(theVector, childtype,
        std::forward<Arg1>(arg1), std::forward<Arg2>(arg2));
    addChildren(theVector, std::forward<Rest>(rest)...);
}

template<class... Args>
vector<unique_ptr<Parent>> CreateVec(Args&&... args)
{
    vector<unique_ptr<Parent>> result;
    addChildren(result, std::forward<Args>(args)...);
    return result;

}

我在这里假设存在函数addChild,该函数可以根据给定的类型(作为参数)和参数来添加子项。

这样做的主要问题是VS2012没有可变参数模板。有两种方法来模拟可变参数模板。 1.编写一个函数,该函数将使用可能需要的最大数量的参数,并将大多数参数默认设置为某种已知类型,您可以将其表示为“不存在”。 2.写出您认为需要的尽可能多的重载。

如果您知道自己不需要多于10个子对象,那么第二种选择实际上是完全可行的-您只需要编写一次即可,而且大概少于150行代码。另外,您可以使用Boost.Preprocessor生成函数,但这是全新的复杂性。

关于c++ - C++:多态容器,可以一次添加多个对象,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14235678/

10-11 22:42
查看更多