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
的元素是不可移动的;unique_ptr
是只能移动的。 - 可变参数模板似乎无法满足使
V
恒定的目标。由于initializer_list
不能容纳不同类型的物体(就像vector
一样(,我首先想到了它们,但是,如何?在阅读了许多示例之后,我仍然无法弄清楚如何制作可变参数模板构造函数,或者即使可以在没有解决方法的情况下做到这一点(即:创建一些需要Base
的 init(( 函数,一个Derived
,...并玩它(。 - 创建一个返回
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
构造函数中的参数包被扩展并以逗号分隔放入用于初始化V
的initializer_list
时,它抱怨调用unique_ptr
的[已删除]复制构造函数的使用。
我想我的问题归结为一个vector
,事实上,可以应用于一个:vector<unique_ptr<Base>>( /* initialize with derived classes */ )
。我认为这之前一定已经解决了,因为多态性是基本C++,并且持有派生类的对象似乎是它的一种非常常见的用法。请注意,我使用g++ 4.8.1
.
提前谢谢。此致敬意卡尔里什
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;
}
相关文章:
- 何时为派生类初始化 vptr?
- 初始化派生结构的基部分/意外打包派生结构字段以对齐基结构的间隙
- 为什么基类数据在派生类数据之前初始化
- C++初始化之前派生类调用基类的方法
- std::数组派生类聚合初始化
- 如何使用派生类类型数据初始化 std::shared_ptr?
- 将已初始化的基类分配给派生类
- 在派生类的构造函数初始化中无法访问受保护的函数
- OOP - 抽象类类型,初始化基类和派生类中的变量
- C :适当的格式以初始化派生和基础
- 初始化 MFC 中 CFormView 派生类的成员数据
- 派生类的聚合初始化
- 初始化基类和派生类中的类成员变量
- C++派生类的初始化列表
- C++ - 在派生类中静态初始化受基类保护的成员变量
- 为什么派生类成员的初始化值在转换为基指针时不会丢失?
- 如何在派生类中初始化继承的模板POD结构
- 如何在 switch 语句中正确初始化不同的派生类
- 如何在派生构造函数的大括号中初始化基构造函数?C++
- 用派生的类构造函数初始化对象