在C中包装C++:派生到基本转换

Adr*_*ian 5 c c++ oop standard-layout

我将一个简单的C++继承层次结构包装成"面向对象的"C.我试图弄清楚是否有任何问题将C++对象的指针视为指向不透明C结构的指针.特别是,在什么情况下派生到基础的转换会导致问题?

类本身相对复杂,但层次结构很浅并且仅使用单继承:

// A base class with lots of important shared functionality
class Base {
    public:
    virtual void someOperation();
    // More operations...

    private:
    // Data...
};

// One of several derived classes
class FirstDerived: public Base {
    public:
    virtual void someOperation();
    // More operations...

    private:
    // More data...
};

// More derived classes of Base..
Run Code Online (Sandbox Code Playgroud)

我计划通过以下相当标准的面向对象的C向C客户端展示它:

// An opaque pointers to the types
typedef struct base_t base_t;
typedef struct first_derived_t first_derived_t;

void base_some_operation(base_t* object) {
     Base* base = (Base*) object;
     base->someOperation();
}

first_derived_t* first_derived_create() {
     return (first_derived_t*) new FirstDerived();
}

void first_derived_destroy(first_derived_t* object) {
     FirstDerived* firstDerived = (FirstDerived*) object;
     delete firstDerived;
}
Run Code Online (Sandbox Code Playgroud)

C客户端只传递指向底层C++对象的指针,并且只能通过函数调用来操作它们.所以客户端最终可以执行以下操作:

first_derived_t* object = first_derived_create();
base_some_operation((base_t*) object); // Note the derived-to-base cast here
...
Run Code Online (Sandbox Code Playgroud)

并按预期成功对FirstDerived :: someOperation()进行虚拟调用.

这些类不是标准布局,但不使用多重或虚拟继承.这保证有效吗?

请注意,如果重要的话,我可以控制所有代码(C++和C包装器).

And*_*ron 4

// An opaque pointers to the types
typedef struct base_t base_t;
typedef struct first_derived_t first_derived_t;

// **********************//
// inside C++ stub only. //
// **********************//

// Ensures you always cast to Base* first, then to void*,
// then to stub type pointer.  This enforces that you'll
// get consistent a address in presence of inheritance.
template<typename T>
T * get_stub_pointer ( Base * object )
{
     return reinterpret_cast<T*>(static_cast<void*>(object));
}

// Recover (intermediate) Base* pointer from stub type.
Base * get_base_pointer ( void * object )
{
     return reinterpret_cast<Base*>(object);
}

// Get derived type pointer validating that it's actually
// the right type.  Returs null pointer if the type is
// invalid.  This ensures you can detect invalid use of
// the stub functions.
template<typename T>
T * get_derived_pointer ( void * object )
{
    return dynamic_cast<T*>(get_base_pointer(object));
}

// ***********************************//
// public C exports (stub interface). //
// ***********************************//

void base_some_operation(base_t* object)
{
     Base* base = get_base_pointer(object);
     base->someOperation();
}

first_derived_t* first_derived_create()
{
     return get_stub_pointer<first_derived_t>(new FirstDerived());
}

void first_derived_destroy(first_derived_t* object)
{
     FirstDerived * derived = get_derived_pointer<FirstDerived>(object);
     assert(derived != 0);

     delete firstDerived;
}
Run Code Online (Sandbox Code Playgroud)

这意味着您始终可以执行如下所示的转换。

first_derived_t* object = first_derived_create();
base_some_operation((base_t*) object);
Run Code Online (Sandbox Code Playgroud)

这是安全的,因为base_t*指针将先转换为void*,然后转换为Base*。这比之前少了一步。注意顺序:

  1. FirstDerived*
  2. Base*(通过隐式static_cast<Base*>
  3. void*(通过static_cast<void*>
  4. first_derived_t*(通过reinterpret_cast<first_derived_t*>
  5. base_t*(via (base_t*),这是 C++ 风格的reinterpret_cast<base_t*>
  6. void*(通过隐式static_cast<void*>
  7. Base*(通过reinterpret_cast<Base*>

对于包装方法的调用FirstDerived,您会得到额外的转换:

  1. FirstDerived*(通过dynamic_cast<FirstDerived*>