好吧,我最近遇到了一个让我分心的情况,如下所示:
class Derived: public Base {
public:
PyObject *GetPyObj() { return m_obj; }
void SetPyObj(PyObject *obj) { m_obj = obj }
private:
PyObject *m_obj;
};
这个类向基类添加了一个附加m_obj
属性,不幸的是,我在代码中的某个地方有一个完全不安全的强制转换,如下所示:
Derived *node = <Derived *>some_ObjectPtr;
// Where "some_ObjectPtr" had been created as a "Base*" in the first place.
当我打电话时,这有时会导致一些任意行为SetPyObj()
。感谢Valgrind
,我已经能够确定我正在“写超出我的对象的末尾”并找到问题:
...
==5679==
==5679== Invalid write of size 8
==5679== at 0x812DB01: elps::Derived::SetPyObj(_object*) (ALabNetBinding.cpp:27)
==5679== by 0x8113B2C: __pyx_f_5cyelp_12PyLabNetwork_Populate(__pyx_obj_5cyelp_PyLabNetwork*, int, int) (cyelp.cpp:10112)
...
我的第一次尝试是将m_obj
Base 类转换为 a void*
,并将其转换SetPyObj()
为 this :
void SetPyObj(PyObject *obj) {
this->SetObj(obj);
}
Base::SetObj(obj)
看起来像这样:
void SetObj(void *obj);
(我选择了void *
,因为出于某些充分的原因, Base 定义中没有 PyObject 类型......)
这样我写到父类,问题就消失了,但仍然......
我对这种操作不放心,对解决方法也不是很满意(这看起来不是一个好的做法,我能闻到它的味道!)。
所以,这是我的问题:
只要我Base
通过仅使用其他方法(没有其他成员变量)的类扩展我所做的事情是否“可以接受”?
如果不是,那么在这种情况下是否可以接受沮丧?在哪些情况下可以接受向下转换(我的意思是除了首先创建some_ObjectPtr
为 a之外Derived*
)?
如果是,那么处理这种情况的优雅方法是什么?
注意:dynamic_cast<>
在我的环境中使用类似的功能不是一个选项(Cython 不可用),我不确定它是否会有所帮助。
额外的第二个问题:您能解释一下如何处理给定类实例的内存大小吗?我可以清楚地看到,在我的示例中,附加属性按其大小(64 位)溢出,但添加一个方法似乎是安全的(这是否意味着如果派生类仅包含附加方法,则派生类和基类都会生成完全相同的尺寸?)。
我希望我把我的担忧说清楚了。