将多态成员变量实例化为适当的类型

Posted

技术标签:

【中文标题】将多态成员变量实例化为适当的类型【英文标题】:Instantiate polymorphic member variable to be of appropriate type 【发布时间】:2015-05-04 15:20:37 【问题描述】:

我有一个基类,其中包含一个成员变量 std::unique_ptr 接下来。我有几个 Base 的派生类。

我有一个非虚拟函数 Base::grow() 接下来初始化。 next 将始终指向调用增长的对象类型的对象。

通过 Base::grow() 中的虚函数调用保证下一个是正确的类型。

为每个派生类创建一个虚函数既麻烦又容易出错,因此我的问题是:我可以更简洁地做到这一点吗?

我当前的最小工作示例如下所示:

#include <iostream>
#include <memory>

class Base
  public:
    static const unsigned SIZE = 3;
    std::unique_ptr<Base> next;
    void grow(unsigned index)
      if (index < SIZE)
        print();
        next = get_new();
        next.get()->grow(index + 1);
      
    

    virtual std::unique_ptr<Base> get_new()
       return std::unique_ptr<Base>(new Base());
      //return std::move(std::unique_ptr<Base>(new Base())); (move not nec. see comments)
    

    virtual void print ()
      std::cout << "a Base ";
    
;

class Derived: public Base
  public:
    virtual void print ()
      std::cout << "a Derived ";
    
    virtual std::unique_ptr<Base> get_new()
      return std::unique_ptr<Base>(new Derived());
    
;

int main()
  std::unique_ptr<Base> b;
  b = std::unique_ptr<Base> (new Base());
  b->grow(0);

  std::unique_ptr<Base> c;
  c = std::unique_ptr<Base> (new Derived());
  c->grow(0);

输出是正确的:a Base a Base a Derived a Derived a Derived

总而言之:我想要一个消除繁琐的 get_new 的解决方案,我希望 Base::grow 根据调用对象的类型确定要创建的类型。我考虑过使用 decltype,但没有成功。

与尝试在运行时确定类型相关的代码 sn-p:

typedef std::remove_reference<decltype(*this)>::type DynamicBase;
next = std::unique_ptr<DynamicBase>(new DynamicBase()); 

上面的DynamicBase总是被确定为Base,即使this是指向Derived的指针

【问题讨论】:

C++ 在运行时没有可靠的方法来获取“调用对象”的类型(除非“调用对象”是指this——你可以获得 limited 关于通过 RTTI 的信息),即使这样,您也需要一些反射能力来创建该类型的新对象。简而言之,没有满足您特定要求的答案,因为它无法在 C++ 中完成。如果您对他们持开放态度,可能会有其他选择。 你不需要move这个表达式std::unique_ptr&lt;Base&gt;(new Base()),它已经是一个右值了。 @cdhowie 我认为该评论应该是一个答案。 @cdhowie 是的,我的意思是“调用对象”。我在我的问题中附加了使用 RTTI 确定类型的尝试,也许您可​​以详细说明它失败的原因(使用我的方法确定的类型始终是 Base) RTTI 应该给你 Derived 类型,如果那是对象的实际类型;如果它给了你Base 我需要查看示例代码来确定原因。但是,即使您拥有 std::type_info 对象,除了将其名称作为字符串并将其与其他 std::type_info 对象进行比较之外,您也无能为力。 C++ 不提供从std::type_info 对象构造新对象的方法。 【参考方案1】:

您想要的是不可能的:您至少需要一个虚函数调用,即在每个派生中都覆盖一个虚方法。例如,考虑派生类在另一个编译单元中定义的情况。如果不使用多态,基类的代码如何获得一个新的未知类型的派生对象?

【讨论】:

在每个类中都需要重写 get_new 是有道理的。但是由于虚函数基本相同,如果有一些类似模板的方法来自动生成它们会很好。【参考方案2】:

昨天我第一次遇到奇怪重复的模板模式(crtp),我很确定它可以用于get_new 只定义一次。

crtp 的思想在这里解释得很好:https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/

【讨论】:

以上是关于将多态成员变量实例化为适当的类型的主要内容,如果未能解决你的问题,请参考以下文章

第六章 类型和成员基础

java中,在实例化一个类时,这个类中没有初始值的int类型成员变量i,i的值是否0?

阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第7节 内部类_15_类作为成员变量类型

多态

多态1

C++中,类内的成员变量自动初始化为零吗,而全局变量随意赋值