Это будет делать то же самое (ничего, по сути). Но это не то же самое, что если бы ты не написал это. Потому что для написания деструктора потребуется рабочий деструктор базового класса. Если деструктор базового класса является закрытым или если по какой-либо другой причине он не может быть вызван, то ваша программа неисправна. Учтите это
struct A { private: ~A(); };
struct B : A { };
Это нормально, если вам не требуется уничтожать объект типа B (и, следовательно, неявно типа A) - например, если вы никогда не вызываете delete для динамически создаваемого объекта или никогда не создаете объект об этом в первую очередь. Если вы это сделаете, то компилятор отобразит соответствующую диагностику. Теперь, если вы предоставите один явно
struct A { private: ~A(); };
struct B : A { ~B() { /* ... */ } };
Тот попытается неявно вызвать деструктор базового класса и вызовет диагностику уже во время определения ~B
.
Существует еще одно различие, которое сосредоточено вокруг определения деструктора и неявных вызовов членов-деструкторов. Рассмотрим этот умный указатель
struct C;
struct A {
auto_ptr<C> a;
A();
};
Предположим, что объект типа C
создан в определении конструктора A в файле .cpp
, который также содержит определение struct C
. Теперь, если вы используете struct A
и требуете уничтожения объекта A
, компилятор предоставит неявное определение деструктора, как в случае выше. Этот деструктор также будет неявно вызывать деструктор объекта auto_ptr. И это приведет к удалению имеющегося у него указателя, указывающего на объект C
- без знания определения C
! Это появилось в файле .cpp
, где определен конструктор структуры A.
На самом деле это распространенная проблема в реализации идиомы pimpl. Решением здесь является добавление деструктора и предоставление его пустого определения в файле .cpp
, где определена структура C
. В тот момент, когда он вызывает деструктор своего члена, он узнает определение struct C
и может правильно вызвать его деструктор.
struct C;
struct A {
auto_ptr<C> a;
A();
~A(); // defined as ~A() { } in .cpp file, too
};
Обратите внимание, что boost::shared_ptr
не имеет этой проблемы: вместо этого требуется полный тип, когда его конструктор вызывается определенным образом.
Еще один момент, в котором это имеет значение в текущем C ++, - это когда вы хотите использовать memset
и друзей для такого объекта, у которого пользователь объявил деструктор. Такие типы больше не являются POD (обычные старые данные), и их нельзя копировать битами. Обратите внимание, что это ограничение на самом деле не нужно - и следующая версия C ++ улучшила ситуацию, позволив вам по-прежнему копировать биты таких типов до тех пор, пока не будут внесены другие более важные изменения.
Так как вы попросили конструкторов: ну, для этого почти все то же самое верно. Обратите внимание, что конструкторы также содержат неявные вызовы деструкторов. В таких вещах, как auto_ptr, эти вызовы (даже если они на самом деле не выполняются во время выполнения - чистая возможность здесь уже имеет значение) принесут тот же вред, что и для деструкторов, и произойдут, когда что-то в конструкторе вызовет - тогда компилятору потребуется вызвать деструктор членов. В этом ответе используется неявное определение конструкторов по умолчанию.
Кроме того, то же самое верно для видимости и PODness, которые я сказал о деструкторе выше.
Есть одно важное отличие в отношении инициализации. Если вы поместите конструктор, объявленный пользователем, ваш тип больше не получит инициализацию значений членов, и ваш конструктор должен выполнить любую необходимую инициализацию. Пример: * * тысяча сорок-две
struct A {
int a;
};
struct B {
int b;
B() { }
};
В этом случае всегда верно следующее
assert(A().a == 0);
Хотя следующее поведение не определено, потому что b
никогда не инициализировался (ваш конструктор пропустил это). Значение может быть нулевым, но может быть и любым другим странным значением. Попытка чтения из такого неинициализированного объекта приводит к неопределенному поведению.
assert(B().b == 0);
Это также верно для использования этого синтаксиса в new
, например new A()
(обратите внимание на круглые скобки в конце - если они опущены, инициализация значения не выполняется, и поскольку не существует объявленного пользователем конструктора, который мог бы его инициализировать , a
останется неинициализированным).