Я думаю, что эти две строки являются суть вопроса:
first_derived_t* object = first_derived_create();
base_some_operation((base_t*) object); // Note the derived-to-base cast here
...
Нет действительно безопасного способа разрешить это в коде C.В C такое приведение никогда не изменяет необработанное целочисленное значение указателя, но иногда приведение C ++ будет делать это, и поэтому вам нужен дизайн, который никогда не будет иметь приведений в коде C.
Вот один из них (чрезмерносложное?) решение.Во-первых, определитесь с политикой, что код C всегда будет строго иметь дело со значением, которое фактически является Base*
- это несколько произвольная политика для обеспечения согласованности.Это означает, что код C ++ иногда должен быть в dynamic_cast, мы вернемся к этому позже.
(Вы можете заставить проект работать правильно с кодом C, просто используя приведение, как уже упоминалось другимиНо я был бы обеспокоен тем, что компилятор разрешит все виды сумасшедших приведений, таких как (Derived1*) derived2_ptr
или даже приведение типов к другой иерархии классов. Моя цель здесь состоит в том, чтобы обеспечить правильную объектно-ориентированную -a отношения в коде C.)
Тогда классы дескрипторов C могут быть примерно такими:
struct base_t_ptr {
void * this_; // holds the Base pointer
};
typedef struct {
struct base_t_ptr get_base;
} derived_t_ptr;
Это должно упростить использование чего-то вроде приведений в сжатом видеи безопасный способ: обратите внимание, как мы передаем object.get_base
в этом коде:
first_derived_t_ptr object = first_derived_create();
base_some_operation(object.get_base);
, где объявление base_some_operation
extern "C" base_some_operation(struct base_t_ptr);
Это будет довольно безопасно для типов, так как вы выигралине сможет передать производный_т_птр в эту функцию без использования элемента данных .get_base
.Это также поможет вашему коду на C немного узнать о типах и о том, какие преобразования допустимы - вы не хотите случайно конвертировать Derived1 в Derived2.
Затем при реализации не виртуальных методов, определенных только в производном классе, вам понадобится что-то вроде:
extern "C" void derived1_nonvirtual_operation(struct derived1_t_ptr); // The C-style interface. Type safe.
void derived1_nonvirtual_operation(struct derived1_t_ptr d) {
// we *know* this refers to a Derived1 type, so we can trust these casts:
Base * bp = reinterpret_cast<Base*>(d.get_base.this_);
Derived1 *this_ = dynamic_cast<Derived1*>;
this_ -> some_operation();
}