我正在使用一个用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()
中的初始化代码更改为更详细,但我认为这是适当解决方案的小价格。
对于你的问题它并不重要,因为“客户端”代码只关心有一个有效的Base*
指针:他们不会在Derived或其他任何东西中转发它,或者复制它。