![](/img/trans.png)
[英]why can't I cast a pointer to Derived class member function to the same but of class Base?
[英]Why can't I instantiate a reference to a base class at the same time as a pointer to a derived class?
我的问题的最简单示例可以在以下代码段中看到:
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
的内部资源aDerived
到derived
,合理地重置aDerived
的状态。 因此,只要您的代码到达语句
base(*aDerived)
base
将引用一个空对象 (取决于您在Base和Derived类中的move构造函数实现),该对象很可能在构造函数本身调用后从内存中删除。
因此,我相信您在代码中获得的对base
任何引用都指向未分配的内存,从而导致SEG_FAULT错误。
SEG_FAULT大部分时间是指正在使用的代码(在编写本示例时,请参见setval())未为运行中的进程分配(尚未分配)的内存区域。
希望这会有所帮助,晚安,斯特凡诺
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.