我想基于另一个只能在运行时知道类型的对象在堆上创建一个新对象。
对于一个假设的例子,假设我们有一个游戏,用户选择一个向导,战士或治疗者的角色。计算机将创建匹配的非玩家角色以对抗玩家。也就是说,如果玩家选择了战士,计算机将生成另一个战士实例。
我正在尝试使用多态性。说向导,战士和治疗师都继承自“战斗类型”类
我想做的是像伪代码:
combattype* player = new (chosen at runtimetype)();//player
combattype* baseptr = new typeid(*player); // computer - this doesn't work
我知道我可以用
之类的东西写一个if语句if(typeid(player).name(*player) == typeid.name(warrior)) { // make warrior}
但是这会很快变得复杂,有数百种类型。我觉得有更好的方法,但我无法在概念上提出它。
我正在尝试做与此问题相似的事情,但在c ++中:Dynamically create an object of <Type> 谢谢你的帮助。
答案 0 :(得分:4)
这(如果我理解正确的话)被称为¹克隆。只需在基类中添加虚拟6
成员函数即可。在每个具体派生类中重写它。
核心功能的示例:
clone
使用返回class Base
{
private:
// Whatever
public:
virtual auto clone() const
-> Base*
{ return new Base( *this ); }
virtual ~Base() {}
};
class Derived_A
: public Base
{
public:
auto clone() const
-> Derived_A* // OK, covariant return type.
override
{ return new Derived_A( *this ); }
};
#include <assert.h>
#include <typeinfo>
auto main()
-> int
{
Base const& o = Derived_A{};
auto p = o.clone();
assert( typeid( *p ) == typeid( Derived_A ) );
delete p; // ← Manual cleanup is a problem with basic cloning.
}
而不是通用clone
的函数覆盖Derived_A*
函数是正常的,因为它是一个原始指针,结果类型是协变的(在更具体的类中更具体) ,即以与类特异性相同的方式变化。对于原始参考,它也可以很好地工作。但是C ++不直接支持类类型函数结果,并且包括智能指针作为Base*
函数结果。
正如评论所指出的,直接,简单克隆的一个问题是清理责任不明确。最好是自动化和保证,但然后一个遇到无支持协变智能指针问题。令人高兴的是,通过使虚拟clone
函数非 - clone
,并在每个类中提供特定于类的智能指针结果包装函数,可以“手动”实现协方差。
使用协变智能指针结果进行克隆的示例:
public
根据中间人继承的概念,以下是在#include <memory> // std::unique_ptr
class Base
{
private:
// Whatever, and
virtual auto virtual_clone() const
-> Base*
{ return new Base( *this ); }
public:
auto clone() const
{ return std::unique_ptr<Base>( virtual_clone() ); }
virtual ~Base() {}
};
class Derived_A
: public Base
{
private:
auto virtual_clone() const
-> Derived_A* // OK, covariant return type.
override
{ return new Derived_A( *this ); }
public:
auto clone() const
{ return std::unique_ptr<Derived_A>( virtual_clone() ); }
};
#include <assert.h>
#include <typeinfo>
auto main()
-> int
{
Base const& o = Derived_A{};
auto p = o.clone();
assert( typeid( *p ) == typeid( Derived_A ) );
// Automatic cleanup.
}
和Base
中自动生成克隆支持机制的一种方法:
Derived_A
你会像这样使用它:
#include <memory> // std::unique_ptr
#include <utility> // std::forward
// Machinery:
template< class Derived_t >
class With_base_cloning_
{
private:
auto virtual virtual_clone() const
-> Derived_t*
{ return new Derived_t( *static_cast<Derived_t const*>( this ) ); }
public:
auto clone() const
{ return std::unique_ptr<Derived_t>( virtual_clone() ); }
virtual ~With_base_cloning_() {}
};
template< class Derived_t, class Base_t >
class With_cloning_
: public Base_t
{
private:
auto virtual_clone() const
-> Base_t* // Ungood type because Derived_t is incomplete here.
override
{ return new Derived_t( *static_cast<Derived_t const*>( this ) ); }
public:
auto clone() const
{ return std::unique_ptr<Derived_t>( static_cast<Derived_t*>( virtual_clone() ) ); }
template< class... Args >
With_cloning_( Args... args )
: Base_t( std::forward<Args>( args )... )
{}
};
// Usage example:
class My_base
: public With_base_cloning_<My_base>
{};
class Derived_A
: public With_cloning_<Derived_A, My_base>
{};
#include <assert.h>
#include <typeinfo>
auto main()
-> int
{
My_base const& o = Derived_A{};
auto p = o.clone();
assert( typeid( *p ) == typeid( Derived_A ) );
// Automatic cleanup.
}
中(私有)virtual_clone
函数的返回类型并不是人们想要的,不是理想的,因为派生类在模板实例化时尚未完成,所以编译器还不知道它是从模板实例化派生的。
这种中间人继承解决方案的替代方案,包括一个简单的代码生成宏,以及虚拟继承层次结构中的(复杂)优势。
¹With_cloning_
函数,在底部调用派生类最多的'复制构造函数,是virtual constructor idiom的一个特例。另一个特例是clone
函数,它在底部调用派生类最多的默认构造函数。
功能