[英]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
是可移动的 。 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). Base
, Derived
,...的init()函数。和它一起玩。 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
扩展中的参数包和以逗号分隔的逗号分隔放入将用于初始化V
的initializer_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.