繁体   English   中英

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

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

我有一个关于多态性, 也许其他技术问题。 考虑以下方案:

#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? */ )
        { }
}

在这里,我有三个类:一个叫做Base的基类; 派生类,称为Derived ; 和最后一堂课, group ,这将作为一个包装来保存Base指针。 但我想实现以下目标:

  • 使用移动语义 不应该涉及副本。 调用者应该能够为构造函数提供几个临时值 ,因为构造函数会窃取它们:

     group my_wonderful_group( Base( /* parameters */ ) , Derived ( /* ... */ ) , Derived ( /* ... */ ) ); 
  • 在初始化列表中初始化V 这样, V可以是const限定的(尽管在初始化列表中初始化成员对象具有所有其他好处)。

我尝试了几件事,但它们要么看起来不合适,要么在概念上远离我的目标:

  • initializer_list s'元素是不可移动的 ; unique_ptr可移动的
  • 变量模板似乎无法满足制作V const的目标。 由于initializer_list不能保存不同类型的对象(就像vector s一样),我首先考虑过它们,但是,如何? 在阅读了很多例子之后,我仍然无法弄清楚如何制作一个可变参数模板构造函数 ,或者即使没有解决方法也可以这样做(即:创建一些带有BaseDerived ,...的init()函数。和它一起玩。
  • 创建一个返回unique_ptr<Base>的函数,并将其参数转发给Derived的构造函数,从而充当group类的用户友好包装器。 然而,这确实没有意义,正如我用下面的代码说明的那样。

这就是我所拥有的:

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

然而,当group扩展中的参数包和以逗号分隔的逗号分隔放入用于初始化Vinitializer_list ,它抱怨使用被调用的unique_ptr的[已删除]复制构造函数。

我想我的问题归结为一个vector ,实际上,它可以应用于一个: vector<unique_ptr<Base>>( /* initialize with derived classes */ ) 我认为这之前必须已经解决,因为多态性是基本的C ++,而派生类的持有对象似乎是它的一种非常常见的用法。 作为一个注释,我使用g++ 4.8.1

提前致谢。 最诚挚的问候,Kalrish

PS:我刚读过这个问题 ,似乎部分地解决了我的问题。

以下应解决您的所有问题:

#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