Двойное наследование с не виртуальным дистрибутором (Y-образным) - PullRequest
0 голосов
/ 18 января 2019

У меня есть Y-образная иерархия классов: класс C наследуется от A и B, а класс D наследуется от C. A и B имеют виртуальные деструкторы, а деструктор C не является виртуальным. Я знаю, что если нет двойного наследования (скажем, нет B), ~ C () будет виртуальным. Мой вопрос: влияет ли на это двойное наследование?

class A { virtual ~A(); ...};
class B { virtual ~B(); ...};
class C : public A, public B { ~C(); ...};
class D : public C { virtual ~D(); ... };

Мне нужно удалить экземпляры класса D через указатель на C.

C* c = new D;
delete c;

Я подозреваю, что в некоторых угловых случаях ~ B () не выполняется - возможно ли это? Может ли это зависеть от уровня оптимизации? Должно ли определение для D присутствовать в файле .cc, где вызывается «delete c»?

Все деструкторы, кроме ~ B (), являются nops, класс C является пустым классом: нет элементов данных, нет функций, только тривиальный конструктор и пустой деструктор. Я написал несколько тестовых программ во всех случаях ~ B () был выполнен, но я уверен, что я не пробовал все возможные комбинации.

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Насколько я знаю, цепочка деструкторов не имеет ничего общего с виртуальным деструктором. Пока вызывается деструктор определенного класса, он автоматически вызывает для вас дескрипторы базового класса.

Виртуальность Desctructor появляется, когда вы удаляете экземпляр производного класса через указатель базового класса.

В приведенном выше примере предполагается, что ~C не является виртуальным (т. Е. Вы не объявляете виртуальный для какого-либо деструктора), и если вы удаляете экземпляр D через C*, дескриптор D может быть пропущен , и компилятор будет вместо вас вызывать ~C. Как упоминалось выше, вызов ~C вызовет автоматический вызов всех уничтожителей базового класса (~A & ~B).

Однако, если вы уже объявили деструктор виртуальным в базовом классе (A и т. Д.), Виртуальность будет распространяться на деструктор всех производных классов. Это означает, что даже если вы не объявили ~C виртуальным, оно фактически является виртуальным.

0 голосов
/ 18 января 2019

C деструктор неявно виртуален, так как по крайней мере один из его базовых деструкторов является виртуальным.

Таким образом, поскольку деструктор C является виртуальным и вы удаляете через указатель на C, будет вызван деструктор D.

Если деструктор A или B не будет виртуальным, удаление объекта D будет неопределенным, но здесь это не так.

Если класс C является производным от класса (классов), то он знает, как уничтожить свои базовые классы. Таким образом, B деструктор будет вызываться всегда (при условии, что вы удаляете либо конечный объект, либо с уровня, где деструктор является виртуальным, явно или неявно.

На практике, даже в неопределенном случае (только деструктор D является виртуальным и объект удаляется с помощью указателя C), деструктор B, вероятно, был бы вызван, но часть D не была бы должным образом уничтожена , Но поскольку он не определен, вы не можете полагаться на это .

0 голосов
/ 18 января 2019

Деструктор Си не виртуален.

Да, это так. У него есть база (базы) с виртуальным деструктором (ами), поэтому деструктор C неявно виртуален. Является ли деструктор объявленным виртуальным явно или нет, не имеет значения. То же самое касается деструктора Д.

Мне нужно удалить экземпляры класса D через указатель на C.

Я подозреваю, что в некоторых угловых случаях ~ B () не выполняется - возможно ли это?

Пока деструктор C является виртуальным, проблем нет. Если деструктор C не был виртуальным, то удаление объекта с помощью указателя на C будет иметь неопределенное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...