简体   繁体   English

C ++ - 多态:使用派生类初始化容器类

[英]C++ - polymorphism: initialization of a container class with derived classes

I have a question regarding polymorphism and maybe other techniques. 我有一个关于多态性, 也许其他技术问题。 Consider the following scheme: 考虑以下方案:

#include <vector>
#include <memory>

using namespace std;

struct Base
{ };

struct Derived : Base
{ };

class group
{
    private:
        vector< unique_ptr<Base> > V;
    public:
        group( /* what to put here? */ )
        : V( /* again: how to construct V? */ )
        { }
}

Here, I have three classes: a base class, called Base ; 在这里,我有三个类:一个叫做Base的基类; a derived class, called Derived ; 派生类,称为Derived ; and a last class, group , that would act as a wrapper to hold Base pointers. 和最后一堂课, group ,这将作为一个包装来保存Base指针。 But I'd like to achieve the following: 但我想实现以下目标:

  • Use move semantics . 使用移动语义 There should be no copies involved. 不应该涉及副本。 The caller should be able to give the constructor several temporaries , as the constructor would steal them: 调用者应该能够为构造函数提供几个临时值 ,因为构造函数会窃取它们:

     group my_wonderful_group( Base( /* parameters */ ) , Derived ( /* ... */ ) , Derived ( /* ... */ ) ); 
  • Initialize V in the initialization list . 在初始化列表中初始化V That way, V could be const -qualified (despite all the other benefits initializing member objects in initialization lists carries). 这样, V可以是const限定的(尽管在初始化列表中初始化成员对象具有所有其他好处)。

I've tried several things, but they either do not seem appropiate, or are simply conceptually far from my goals: 我尝试了几件事,但它们要么看起来不合适,要么在概念上远离我的目标:

  • initializer_list s' elements are non-movable ; initializer_list s'元素是不可移动的 ; unique_ptr s are movable-only . unique_ptr可移动的
  • Variadic templates do not seem capable to fit the goal of making V const . 变量模板似乎无法满足制作V const的目标。 As initializer_list s can't hold objects of different types (just like vector s), I first thought about them, but, how? 由于initializer_list不能保存不同类型的对象(就像vector s一样),我首先考虑过它们,但是,如何? After reading many examples, I still can't figure out how to make a variadic template constructor , or even if it's possible to do so without a workaround (ie: creating some init() function that takes a Base , a Derived ,... and plays with it). 在阅读了很多例子之后,我仍然无法弄清楚如何制作一个可变参数模板构造函数 ,或者即使没有解决方法也可以这样做(即:创建一些带有BaseDerived ,...的init()函数。和它一起玩。
  • Create a function that returns unique_ptr<Base> and that forwards its arguments to the constructor of Derived , thus acting as an user-friendly wrapper to the group class. 创建一个返回unique_ptr<Base>的函数,并将其参数转发给Derived的构造函数,从而充当group类的用户友好包装器。 This does, however, make little sense, as I illustrate with the code attached below. 然而,这确实没有意义,正如我用下面的代码说明的那样。

This is what I have: 这就是我所拥有的:

#include <string>
#include <vector>
#include <memory>
#include <initializer_list>
#include <iostream>

using namespace std;

struct Base
{
    string s;
    Base(Base && b) : s(move(b.s)) { }
    Base(const string & S) : s( S ) { }
};

struct Derived : Base
{
    Derived(const string & S) : Base( S ) { }
};

unique_ptr<Base>
BASE ( const string & S )
{
    return unique_ptr<Base>( new Base(S) );
}

unique_ptr<Base>
DERIVED ( const string & S )
{
    return unique_ptr<Base>( new Derived(S) );
}

class C
{
    private:
        vector< unique_ptr<Base> > V;
    public:
        template<typename ... T>
            C
            ( T ... t ) : V({ t... })
            { }

        void
            print
            ( void )
            {
                for ( const auto & x : this->V )
                    cout << x->s << endl;
            }
            ;
};


int main(void)
{
    C c( BASE("hola") , DERIVED("der1") , DERIVED("bor3") );
    c.print();
    return 0;
}

It complains, however, about the usage of the [deleted] copy constructor of unique_ptr being called, when the argument pack in the constructor of group is expanded and comma-separated put into the initializer_list that would be used to initialize V . 然而,当group扩展中的参数包和以逗号分隔的逗号分隔放入用于初始化Vinitializer_list ,它抱怨使用被调用的unique_ptr的[已删除]复制构造函数。

I guess that my question goes down to a vector , and, in fact, could be applied to one: vector<unique_ptr<Base>>( /* initialize with derived classes */ ) . 我想我的问题归结为一个vector ,实际上,它可以应用于一个: vector<unique_ptr<Base>>( /* initialize with derived classes */ ) I think this must have been solved before, as polymorphism is basic C++, and holding objects of derived classes seems a very common usage of it. 我认为这之前必须已经解决,因为多态性是基本的C ++,而派生类的持有对象似乎是它的一种非常常见的用法。 As a note, I use g++ 4.8.1 . 作为一个注释,我使用g++ 4.8.1

Thanks in advance. 提前致谢。 Best regards, Kalrish 最诚挚的问候,Kalrish

PS: I've just read this question which seems to partly cover my problem. PS:我刚读过这个问题 ,似乎部分地解决了我的问题。

Following should solve all your issues: 以下应解决您的所有问题:

#include <iostream>
#include <memory>
#include <string>
#include <vector>

using namespace std;

struct Base
{
    string s;
    Base(const Base& b) = delete;
    Base(Base && b) : s(move(b.s)) { }
    Base(const string & S) : s( S ) { }
};

struct Derived : Base
{
    Derived(const string & S) : Base( S ) { }
};

#if 1 // not in C++11
template <typename T, typename ... Ts>
std::unique_ptr<T> make_unique(Ts&&...args)
{
    return std::unique_ptr<T>(new T{std::forward<Ts>(args)...});
}
#endif

// vector<move_only> cannot be construct from initializer list :-/
// Use this work around
template <typename Base, typename ... Ts>
std::vector<std::unique_ptr<Base>> make_vector_of_unique(Ts&&... ts)
{
    std::unique_ptr<Base> init[] = {make_unique<Ts>(std::forward<Ts>(ts))...};
    return std::vector<std::unique_ptr<Base>> {
        std::make_move_iterator(std::begin(init)),
        std::make_move_iterator(std::end(init))};
}

class C
{
private:
    const std::vector< std::unique_ptr<Base> > V;
public:
    template<typename ... Ts>
    C(Ts&& ... t) : V(make_vector_of_unique<Base>(std::forward<Ts>(t)...))
    {}

    void print()
    {
        for (const auto & x : this->V)
            std::cout << x->s << std::endl;
    }
};

int main() {
    C c( Base("hola") , Derived("der1") , Derived("bor3") );
    c.print();
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM