将多态成员变量实例化为适当的类型
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<Base>(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?