我正在使用用C编写的库,该库的继承方式如下:
struct Base
{
int exampleData;
int (function1)(struct Base* param1, int param2);
void (function2)(struct Base* param1, float param2);
//...
};
struct Derived
{
struct Base super;
//other data...
};
struct Derived* GetNewDerived(/*params*/)
{
struct Derived* newDerived = malloc(sizeof struct Derived);
newDerived->super.function1 = /*assign function*/;
newDerived->super.function2 = /*assign function*/;
//...
return newDerived;
}
int main()
{
struct Derived *newDerieved = GetNewDerived(/*params*/);
FunctionExpectingBase((struct Base*) newDerived);
free(newDerived);
}
我的理解是可行的,因为指向
Derived
的指针与指向Derived
的第一个成员的指针相同,因此强制转换指针类型足以将对象视为其“基类”。我可以写任何分配给function1
和function2
的东西,以将传入指针从Base*
转换为Derived*
来访问新数据。我正在扩展这样的代码功能,但是我正在使用C++编译器。我想知道下面是否等同于上面。
class MyDerived : public Base
{
int mydata1;
//...
public:
MyDerived(/*params*/)
{
function1 = /*assign function pointer*/;
function2 = /*assign function pointer*/;
//...
}
//...
};
int main()
{
MyDerived *newDerived = new MyDerived(/*params*/);
FunctionExpectingBase( static_cast<Base*>(newDerived) );
delete newDerived;
}
我是否可以期望编译器以相同的方式在
MyDerived
中布置内存,以便我可以执行相同的指针转换以将对象传递到其代码中?还是我必须继续像他们的C架构那样编写代码,而不是利用C++编译器为我做一些更乏味的工作?在此问题的范围内,我仅考虑单一继承。
最佳答案
根据Adding a default constructor to a base class changes sizeof() a derived type和When extending a padded struct, why can't extra fields be placed in the tail padding?,即使您仅将构造函数添加到MyDerived
或以其他任何方式使其变为非POD,内存布局也可以更改。因此,恐怕没有这样的保证。实际上,您可以使用适当的编译时断言来验证两种结构的相同内存布局,以使其正常工作,但是这种解决方案似乎并不安全,并且不受标准C++支持。
另一方面,为什么您的C++包装器MyDerived
无法从Derived
继承?这将是安全的(因为将Derived
强制转换为Base
并返回时是安全的,但是我认为那是您无法控制的)。它可能会将MyDerived::MyDerived()
中的初始化代码更改为更详细,但是我想这对于适当的解决方案来说代价很小。