我正在使用用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的第一个成员的指针相同,因此强制转换指针类型足以将对象视为其“基类”。我可以写任何分配给function1function2的东西,以将传入指针从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 typeWhen 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()中的初始化代码更改为更详细,但是我想这对于适当的解决方案来说代价很小。

08-16 19:32