如何从另一个实例的类型动态实例化一个新实例?由 小码哥发布于

Eni*_*134 5 c++ polymorphism dynamic instantiation decltype

我想在堆上基于另一个对象创建一个新对象,该对象的类型只能在运行时知道。

举一个假设的例子,假设我们有一个游戏,用户选择一个角色,可以是巫师、战士或治疗师。计算机会创建一个匹配的非玩家角色来对抗玩家。也就是说,如果玩家选择了一个战士,计算机就会生成另一个战士实例。

我正在尝试使用多态性。假设巫师、战士和治疗师都继承自“Combattype”类

我想做的是类似伪代码的事情:

    combattype* player = new (chosen at runtimetype)();//player
    combattype* baseptr = new typeid(*player);   // computer - this doesn't work
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用类似的东西编写 if 语句

if(typeid(player).name(*player) == typeid.name(warrior)) { // make warrior}
Run Code Online (Sandbox Code Playgroud)

但如果有数百种类型,这很快就会变得复杂。我觉得有更好的方法,但我无法从概念上提出它。

我正在尝试做与此问题类似的事情,但在 c++ 中:Dynamically create an object of <Type> 感谢您的帮助。

Che*_*Alf 4

这(如果我正确理解问题)被称为 \xc2\xb9 cloningclone只需在基类中添加一个虚拟成员函数即可。在每个具体的派生类中重写它。

\n\n
\n\n

核心功能示例:

\n\n
class Base\n{\nprivate:\n    // Whatever\npublic:\n    virtual auto clone() const\n        -> Base*\n    { return new Base( *this ); }\n\n    virtual ~Base() {}\n};\n\nclass Derived_A\n    : public Base\n{\npublic:\n    auto clone() const\n        -> Derived_A*        // OK, covariant return type.\n        override\n    { return new Derived_A( *this ); }\n};\n\n#include <assert.h>\n#include <typeinfo>\nauto main()\n    -> int\n{\n    Base const& o = Derived_A{};\n    auto p = o.clone();\n    assert( typeid( *p ) == typeid( Derived_A ) );\n    delete p;       // \xe2\x86\x90 Manual cleanup is a problem with basic cloning.\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

用返回而不是通用的clone函数覆盖该函数是可以的,因为它是原始指针并且结果类型是协变的(在更具体的类中更具体,即以与类特异性相同的方式变化)。它也可以很好地作为原始参考。但 C++ 并不直接支持类类型函数结果的 this,这包括作为函数结果的智能指针。Derived_A*Base*clone

\n\n

正如评论所指出的,直接、简单克隆的一个问题是清理责任不明确。最好是自动化并有保证,但这样就会遇到不支持协变智能指针的问题。令人高兴的是,可以“手动”实现协变,方法是使虚拟clone函数成为非public,并在每个类中提供特定于类的智能指针结果包装函数。

\n\n
\n\n

使用协变智能指针结果进行克隆的示例:

\n\n
#include <memory>       // std::unique_ptr\n\nclass Base\n{\nprivate:\n    // Whatever, and\n    virtual auto virtual_clone() const\n        -> Base*\n    { return new Base( *this ); }\n\npublic:\n    auto clone() const\n    { return std::unique_ptr<Base>( virtual_clone() ); }\n\n    virtual ~Base() {}\n};\n\nclass Derived_A\n    : public Base\n{\nprivate:\n    auto virtual_clone() const\n        -> Derived_A*        // OK, covariant return type.\n        override\n    { return new Derived_A( *this ); }\n\npublic:\n    auto clone() const\n    { return std::unique_ptr<Derived_A>( virtual_clone() ); }\n};\n\n#include <assert.h>\n#include <typeinfo>\nauto main()\n    -> int\n{\n    Base const& o = Derived_A{};\n    auto p = o.clone();\n    assert( typeid( *p ) == typeid( Derived_A ) );\n    // Automatic cleanup.\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

这是一种基于中间人继承Base概念在和中自动生成克隆支持机制的方法:Derived_A

\n\n
#include <memory>       // std::unique_ptr\n#include <utility>      // std::forward\n\n// Machinery:\ntemplate< class Derived_t >\nclass With_base_cloning_\n{\nprivate:\n    auto virtual virtual_clone() const\n        -> Derived_t*\n    { return new Derived_t( *static_cast<Derived_t const*>( this ) ); }\n\npublic:\n    auto clone() const\n    { return std::unique_ptr<Derived_t>( virtual_clone() ); }\n\n    virtual ~With_base_cloning_() {}\n};\n\ntemplate< class Derived_t, class Base_t >\nclass With_cloning_\n    : public Base_t\n{\nprivate:\n    auto virtual_clone() const\n        -> Base_t*          // Ungood type because Derived_t is incomplete here.\n        override\n    { return new Derived_t( *static_cast<Derived_t const*>( this ) ); }\n\npublic:\n    auto clone() const\n    { return std::unique_ptr<Derived_t>( static_cast<Derived_t*>( virtual_clone() ) ); }\n\n    template< class... Args >\n    With_cloning_( Args... args )\n        : Base_t( std::forward<Args>( args )... )\n    {}\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

你会像这样使用它:

\n\n
// Usage example:\n\nclass My_base\n    : public With_base_cloning_<My_base>\n{};\n\nclass Derived_A\n    : public With_cloning_<Derived_A, My_base>\n{};\n\n#include <assert.h>\n#include <typeinfo>\nauto main()\n    -> int\n{\n    My_base const& o = Derived_A{};\n    auto p = o.clone();\n    assert( typeid( *p ) == typeid( Derived_A ) );\n    // Automatic cleanup.\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

virtual_clonein 中的(私有)函数的返回类型With_cloning_并不是人们想要的,也不理想,因为派生类在模板实例化时尚未完成,因此编译器还不知道它\'源自模板实例化。

\n\n

这种中间人继承解决方案的替代方案包括简单的代码生成宏和虚拟继承层次结构中的(复杂)主导。

\n\n
\n\n

\n\xc2\xb9clone函数在底层调用最底层派生类的复制构造函数,是虚拟构造函数习惯用法的一种特殊情况。另一个特殊情况是create函数,它在底部调用最派生类的默认构造函数。\n

\n