gpt4 book ai didi

c++ - 为什么不能在实例化派生类指针的同时实例化对基类的引用?

转载 作者:行者123 更新时间:2023-11-28 01:44:26 24 4
gpt4 key购买 nike

我的问题最简单的例子可以在下面的代码片段中看到:

class Handle : public IHandle_<Handle>{
public:
Handle(std::unique_ptr<Derived> aDerived)
: derived(std::move(aDerived)),
base(*aDerived) {};

std::unique_ptr<Derived> derived;
Base& base;
};

在这里,您可以看到 Handle 类本质上是 Derived 的包装器。更重要的是,我希望通过引用的方式公开Derived 的基类Base。这样做的原因是,最终,我希望 Handle 看起来像这样:

class Handle : public IHandle_<Handle>{
private:
std::unique_ptr<Derived1> myD1;
std::unique_ptr<Derived2> myD2;

public:
Handle(std::unique_ptr<Derived1> aD1)
: myD1(std::move(aD1)),
base1(*aD1),
base2(*aD1){};
Handle(std::unique_ptr<Derived2> aD2)
: myD2(std::move(aD2)),
base1(*aD2),
base2(*aD2){};

Base1& base1;
Base2& base2;

};

我希望 Handle 像这样工作的原因是我将它用作“实体组件系统”中的“组件”,并且我希望这个特定组件是可从相同的两个基类的两个不同具体实现实例化。我提到这一点是因为根据定义,“实体组件系统”设计模式背离了传统的面向对象编程实践:换句话说,我知道还有其他方法可以完成我想做的事情,但我希望它能在我在此处列出的内容的一些变体。

问题

为什么我的第一个片段中显示的简单 Handle 示例会失败?它编译正常,但在尝试访问 Base 中的方法时会出现段错误。如果我更改实例化 Handle 的成员变量的顺序,我会在编译时遇到一些错误,我认为这可以提供一些提示,但我并不真正理解发生了什么。

这是Handle 及其依赖类的完整工作示例:

#include <memory>
#include <iostream>

class Base{
public:
Base(int ax) : x(ax){};
virtual ~Base() = 0;
virtual void setVal(float a) = 0;
virtual float getVal() = 0 ;

int x;
};

Base::~Base(){}

class Derived : public Base{
public:
Derived(int ax, int az)
: Base(ax), z(az){};

int z;
};

class Concrete : public Derived{
public:
Concrete(int ax, int aw, int av)
: Derived(ax, aw),
v(av){};
void setVal(float a) override{
myVal = a;
}
float getVal() override{
return myVal;
}
float myVal;
int v;
};

class IHandle{
public:
virtual ~IHandle() = 0;
};

IHandle::~IHandle(){}

template <class T>
class IHandle_ : public IHandle{
public:
virtual ~IHandle_() = 0;
};

template <class T>
IHandle_<T>::~IHandle_(){};

class Handle : public IHandle_<Handle>{
public:
Handle(std::unique_ptr<Derived> aDerived)
: derived(std::move(aDerived)),
base(*aDerived) {};

std::unique_ptr<Derived> derived;
Base& base;
};


int main(){
// These two pointers are owned by an EntityManager
std::unique_ptr<Derived> ptr(new Concrete(1, 2, 3));

// we can get a reference to an IHandle from the EntityManager
std::unique_ptr<IHandle> aHandle(new Handle(std::move(ptr)));

// We need, specifically, a `Handle` implementation of `IHandle`
Handle& handle = static_cast<Handle&>(*aHandle);
// seg fault on the following line
handle.base.setVal(10.0);
std::cout << "a = " << handle.base.getVal() << std::endl;
return 0;
}

最佳答案

C++ 类中的成员按照您声明它们的顺序进行初始化,所以看第一个片段,Handle 类中成员的初始化顺序是:

  • 派生
  • 基地

也就是说,这意味着在构造函数中行

derived(std::move(aDerived))

会将aDerived的内部资源转移给derived,合理重置aDerived的状态。所以一旦你的代码到达语句

base(*aDerived)

base 将引用一个(取决于您在 Base 和 Derived 类中的移动构造函数实现)对象,该对象很可能在构造函数调用后从内存中删除本身。

因此,我相信您在代码中对 base 的任何引用都指向未分配的内存,从而产生 SEG_FAULT 错误。

SEG_FAULT 大多数时候指的是正在使用的代码(在您的案例中,请参阅 setval() )未(尚未或不再)分配给正在运行的进程的内存区域。

希望对您有所帮助,祝你晚安,斯特凡诺

关于c++ - 为什么不能在实例化派生类指针的同时实例化对基类的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45747800/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com