Форум программистов, компьютерный форум CyberForum.ru

Наследование - вызов конструкторов и деструкторов - C++

Восстановить пароль Регистрация
 
 
m45
0 / 0 / 0
Регистрация: 06.07.2015
Сообщений: 22
01.11.2015, 02:04     Наследование - вызов конструкторов и деструкторов #1
Делаю два класса - предок и потомок:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class class_1_type {
private:
    int t;
public:
    class_1_type(int t_) { t = t_; cout << "class_1. object: " << this << " - constructor  t = " << t << endl; }
    ~class_1_type() { cout << "class_1. object: " << this << " - destructor  t = " << t << endl; }
};
 
 
class class_2_type: public class_1_type {
private:
    int s;
public:
    class_2_type(int t_, int s_): class_1_type(t_) { s = s_; cout << "class_2. object: " << this << " - constructor  s = " << s << endl; }
    ~class_2_type() { cout << "class_2. object: " << this << " - destructor  s = " << s << endl; }
};
Пишу такой код:
C++
1
2
3
4
5
6
7
8
9
10
11
    class_1_type * ob1;
    class_2_type * ob2;
 
    ob1 = new class_1_type(1);
    delete ob1;
 
    ob1 = new class_2_type(2, 3);
    delete ob1;
 
    ob2 = new class_2_type(4, 5);
    delete ob2;
Получаю такой вывод на экран:
class_1. object: 00343AF8 - constructor t = 1
class_1. object: 00343AF8 - destructor t = 1

class_1. object: 00343AF8 - constructor t = 2
class_2. object: 00343AF8 - constructor s = 3
class_1. object: 00343AF8 - destructor t = 2

class_1. object: 00343AF8 - constructor t = 4
class_2. object: 00343AF8 - constructor s = 5
class_2. object: 00343AF8 - destructor s = 5
class_1. object: 00343AF8 - destructor t = 4
Первый и третий случаи - все понятно.
Подскажите пожалуйста, почему во втором случае не вызвался деструктор класса-наследника??
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
05.11.2015, 14:38     Наследование - вызов конструкторов и деструкторов #21
Fallenworld
Цитата Сообщение от Fallenworld Посмотреть сообщение
наследник не знает открытых методов
Кто угодно знает контракты открытых методов, а не только наследник.
Вот только у наследника больше обязанностей, так как класс предок ещё и супертип.
Приходится и LSP соблюдать, если создаём методы с той же сигнатурой, и ещё на приватные методы смотреть.

Добавлено через 4 минуты
gromo
Я не говорю, что не следует использовать C++... Но пытаться извернуться и исправить ошибки дизайна хаками -- не самый хороший путь.
Что есть, то и используем. Более разумным кажется определять типы чисто-виртуальными функциями. Гораздо меньше проблем.

Добавлено через 17 минут
* * *
Пример, что мы не можем полностью игнорировать то, как устроены "невиртуальные" методы базового класса.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Base {
public:
    std::ostream& hello(std::ostream& stream)
    {
        private_hello(stream);
        return stream;
    }
    
private:
    virtual void private_hello(std::ostream&) =0;
};
 
class Derived: public Base {
public:
    Derived(std::ostream& stream)
    {
        Base::hello(stream);
    }
    
private:
    virtual void private_hello(std::ostream&) =0;
};
 
class NextDerived: public Derived {
public:
    NextDerived(std::ostream& stream): Derived(stream) { }
 
private:
    void private_hello(std::ostream& stream)
    {
        stream << "Hello NextDerived" << std::endl;
    }
};
Нам, оказывается, крайне важно знать, что метод hello нельзя вызвать, если нет метода private_hello.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Ilot
Модератор
Эксперт С++
1767 / 1142 / 223
Регистрация: 16.05.2013
Сообщений: 3,020
Записей в блоге: 5
Завершенные тесты: 1
05.11.2015, 14:55     Наследование - вызов конструкторов и деструкторов #22
Цитата Сообщение от m45 Посмотреть сообщение
Так а почему для конструктора не нужно указывать метод виртуальным?
Потому, что пока не построен объект для него не существует таблицы виртуальных функций. Нельзя выбрать тип конструктора не имея объекта от имени которого эта функция будет вызывается. Виртуальные деструкторы конечно отличаются от простых методов однако ж они вызываются для уже существующих объектов.
gromo
 Аватар для gromo
366 / 265 / 24
Регистрация: 04.09.2009
Сообщений: 1,214
05.11.2015, 14:59     Наследование - вызов конструкторов и деструкторов #23
mporro, метода private_hello не может не быть, ибо он объявлен в самом базовом классе.
И почему у вас в Derived переопределение чисто виртуальной функции в чисто виртуальную?!
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
05.11.2015, 15:32     Наследование - вызов конструкторов и деструкторов #24
gromo
Цитата Сообщение от gromo Посмотреть сообщение
ибо он объявлен в самом базовом классе
Ммм... А почему же его нет? Он есть. В том классе, который создаётся, метод вполне определён.

Цитата Сообщение от gromo Посмотреть сообщение
И почему у вас в Derived переопределение чисто виртуальной функции в чисто виртуальную?!
Для наглядности. Можно вырезать это определение -- ничего не изменится.

The bottom line is: нам необходимо знать, что метод Base::hello нельзя использовать, если не определён метод private_hello, нам необходимо знать детали реализации невиртуальных методов. А если бы мы сразу использовали чисто-виртуальный метод Base::hello, то подобных проблем у нас бы не возникло.

Добавлено через 29 минут
P.S.
Я не спорю, что в определённых ситуациях нечто подобное может потребоваться. Может.
Но! У non-virtual interfaces много ограничений и недостатков, а преимуществ очень мало.
Их следует использовать только в специфических ситуациях, но никак не с такими претензиями, как рекламировал Саттер.
gromo
 Аватар для gromo
366 / 265 / 24
Регистрация: 04.09.2009
Сообщений: 1,214
05.11.2015, 15:51     Наследование - вызов конструкторов и деструкторов #25
mporro, так ведь невиртуальный метод hello, как раз и предназначен, чтобы скрыть это. В нем проверяем все предусловия, инварианты и постусловия. Если на то пошло, то можно в самом базовом классе сделать безобидную заглушку для impl-метода (например, сделать его пустым), которая избавит вас от необходимости делать его пустым в своем подклассе, тобишь "вдаваться в детали".
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
05.11.2015, 17:06     Наследование - вызов конструкторов и деструкторов #26
gromo
Цитата Сообщение от gromo Посмотреть сообщение
как раз и предназначен, чтобы скрыть это
Он ничего не скрывает. В лучшем случае можно говорить о том, что базовый интерфейс диктует стратегию.

То, что я вижу, и почему больше не пишу ничего подобного, это пародия на следующий паттерн:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct TSmallMethods {
public:
   virtual method_A =0;
   virtual method_B =0;
   virtual method_C =0; 
};
 
class StrategicallyPlacedMethods {
public:
    spm_method_A {
        small_methods_provider.method_A;
        small_methods_provider.method_B;
    }
 
    spm_method_B {
        small_methods_provider.method_A;
        small_methods_provider.method_C;
        small_methods_provider.method_B;
    }
 
    StrategicallyPlacedMethods(TSmallMethods& small_methods_provider);
 
private:
    TSmallMethods& small_methods_provider;
};
Только вместо того, чтобы ясно указать "я использую такие-то методы", NVI говорит что-то про отношение является между реализацией, которая использует методы и реализацией, которая эти методы поставляет.
hoggy
5228 / 2119 / 403
Регистрация: 15.11.2014
Сообщений: 4,806
Завершенные тесты: 1
07.11.2015, 11:35     Наследование - вызов конструкторов и деструкторов #27
Цитата Сообщение от mporro Посмотреть сообщение
то теперь к ним ещё прилипнут контракты приватных методов.
противоречие здравому смыслу,
и самой причине существования модификатора доступа private

Добавлено через 1 минуту
Цитата Сообщение от mporro Посмотреть сообщение
и ещё на приватные методы смотреть.
не нужно.
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 11:47     Наследование - вызов конструкторов и деструкторов #28
Цитата Сообщение от hoggy Посмотреть сообщение
не нужно.
Как обычно, только в Ваших фантазиях.
Обсуждать их не имеет смысла.
hoggy
5228 / 2119 / 403
Регистрация: 15.11.2014
Сообщений: 4,806
Завершенные тесты: 1
07.11.2015, 11:52     Наследование - вызов конструкторов и деструкторов #29
Цитата Сообщение от mporro Посмотреть сообщение
Как обычно, только в Ваших фантазиях.
вам часто приходится втыкать в приватные секции библиотечных классов?
скорее всего вы даже не подозреваете об их существовании.
но это не мешает вам продуктивно с ними работать.

так и должно быть с грамотно сконструированным кодом.

необходимость лазить в приваты - последствия вашего личного не совершенства
в этом ужассном и реальном мире.

и кстати, у вас там выше собственность предназначенная для наследников помечена как private
а должна быть protected.
косяк в дизайне и печалька.
gromo
 Аватар для gromo
366 / 265 / 24
Регистрация: 04.09.2009
Сообщений: 1,214
07.11.2015, 12:06     Наследование - вызов конструкторов и деструкторов #30
Цитата Сообщение от hoggy Посмотреть сообщение
у вас там выше собственность предназначенная для наследников помечена как private
а должна быть protected.
Где именно ?
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 12:22     Наследование - вызов конструкторов и деструкторов #31
Цитата Сообщение от hoggy Посмотреть сообщение
так и должно быть с грамотно сконструированным кодом.
Прочитайте статью Саттера.
Там чёрным по белому написано keep virtual functions private.
Вся суть NVI в том, что Вы перегружаете не открытый контракт, а закрытый.
А вот чтобы перегружать закрытый контракт, Вам придётся в него "втыкать".
hoggy
5228 / 2119 / 403
Регистрация: 15.11.2014
Сообщений: 4,806
Завершенные тесты: 1
07.11.2015, 12:47     Наследование - вызов конструкторов и деструкторов #32
Цитата Сообщение от gromo Посмотреть сообщение
Где именно ?
Цитата Сообщение от mporro Посмотреть сообщение
private:
* * virtual void private_hello(std::ostream&) =0;
частная собственность класса наследников не должна касаться.
имя функции-члена тоже доставляет:
"переопределяйте детали реализации"
gromo
 Аватар для gromo
366 / 265 / 24
Регистрация: 04.09.2009
Сообщений: 1,214
07.11.2015, 12:49     Наследование - вызов конструкторов и деструкторов #33
Цитата Сообщение от hoggy Посмотреть сообщение
имя функции-члена тоже доставляет:
"переопределяйте детали реализации"
Прочитайте стать Virtuality Саттера.

Почти вся стандартная библиотека построена на этой идиоме.

Еще часто применяют префикс `do_`. Публичная интерфейсная функция request(), рабочая функция — do_request(), что я нахожу более привлекательным нежели `private_`, но кому как нравится
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 12:51     Наследование - вызов конструкторов и деструкторов #34
hoggy
Сначала, пожалуйста, ознакомьтесь со статьёй Саттера.
Только после этого отвечайте по теме NVI.
Вопросы, которые Вы пытаетесь адресовать мне, следует адресовать Саттеру.
hoggy
5228 / 2119 / 403
Регистрация: 15.11.2014
Сообщений: 4,806
Завершенные тесты: 1
07.11.2015, 13:02     Наследование - вызов конструкторов и деструкторов #35
Цитата Сообщение от mporro Посмотреть сообщение
Там чёрным по белому написано keep virtual functions private.
это может быть нужно только и только,
если существует объективная причина не позволить наследнику
выполнить прямой вызов виртуальной функции базового класса,

хотя на вскидку, мне трудно представить зачем такое может понадобиться.

во всем остальном приватные виртуальные функции-члены не дают никаких преимуществ,
по сравнению с protected

только с толку сбивают.
потому что protected - это то, что доктор прописал специально для наследников.
а private - частная собственность.
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 13:04     Наследование - вызов конструкторов и деструкторов #36
hoggy
Мне то зачем это рассказывать?
Расскажите это Саттеру.
hoggy
5228 / 2119 / 403
Регистрация: 15.11.2014
Сообщений: 4,806
Завершенные тесты: 1
07.11.2015, 13:21     Наследование - вызов конструкторов и деструкторов #37
Цитата Сообщение от mporro Посмотреть сообщение
Мне то зачем это рассказывать?
Расскажите это Саттеру.
мне просто стало любопытно:
вы приводите в качестве аргумента некий авторитет: Саттера.
но понимаете ли вы его?
или вы бездумно верите авторитетам?

вы осознаете, зачем нужно делать виртуальные-функции члены приватными?

я читал Саттера если что.
и мне нет смысла ему что-то рассказывать.

потому что подобный тезис:
Guideline #2: Prefer to make virtual functions private.
That's easy. This lets the derived classes override the function to customize the behavior as needed, without further exposing the virtual functions directly by making them callable by derived classes (as would be possible if the functions were just protected). The point is that virtual functions exist to allow customization; unless they also need to be invoked directly from within derived classes' code, there's no need to ever make them anything but private. But sometimes we do need to invoke the base versions of virtual functions (see the article "Virtually Yours"[5] for an example), and in that case only it makes sense to make those virtual functions protected, thus:

(ц)Саттер.
практически целиком и полностью совпадает с моим собственным (см #35).

разница между моим подходом, и подходом Саттера заключается лишь в одном:
я четко разделяю, что есть частная собственность,
а что предназначено для наследников.

Саттер же стремится в принципе выполнить максимально жесткий контракт.
он стремится сделать приватным все, что только возможно.
и не делает приватным лишь то,
что объективно необходимо сделать не приватным.

что на мой взгляд ухудшает читабельность,
и не несет профита.
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 13:25     Наследование - вызов конструкторов и деструкторов #38
hoggy
Тогда мой Вам ответ состоит в том, что втыкать придётся не только в открытый контракт, который случайно может быть нарушен наследником, но ещё в защищённый (protected) контракт, который тоже нужно соблюдать.
Зачем мне нужна эта лишняя деталь защищённого контракта?

Замена private на protected не решает проблемы лишней детали.
hoggy
5228 / 2119 / 403
Регистрация: 15.11.2014
Сообщений: 4,806
Завершенные тесты: 1
07.11.2015, 13:36     Наследование - вызов конструкторов и деструкторов #39
Цитата Сообщение от mporro Посмотреть сообщение
втыкать придётся не только в открытый контракт
только прототип.
реализация его не интересует.

Цитата Сообщение от mporro Посмотреть сообщение
в защищённый (protected) контракт, который тоже нужно соблюдать.
разумеется. он для того и существует,
что бы разработчик наследника в него втыкал,
и соблюдал.
Цитата Сообщение от mporro Посмотреть сообщение
Зачем мне нужна эта лишняя деталь защищённого контракта?
странный вопрос.
что бы корректно унаследоваться и породить наследника.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.11.2015, 13:56     Наследование - вызов конструкторов и деструкторов
Еще ссылки по теме:

C++ Вызов конструкторов/деструкторов при наследовании
Классы и обьекты в С++. Выполнить исследование вызовов конструкторов и деструкторов C++
Задание с использованием конструкторов и деструкторов C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
mporro
256 / 102 / 14
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 13:56     Наследование - вызов конструкторов и деструкторов #40
Цитата Сообщение от hoggy Посмотреть сообщение
что бы корректно унаследоваться и породить наследника
Чтобы корректно унаследоваться мне достаточно информации об открытом контракте, которая у меня уже есть.
Потому внедрение protected контракта -- это уже излишне. Зачем?

Цитата Сообщение от hoggy Посмотреть сообщение
реализация его не интересует.
Печально, что и это не всегда правда.
Я привёл пример, когда мне необходима информация о том, что определённый невиртуальный метод использует определённый виртуальный. А в жизни таких ситуаций может быть ещё больше. Сомневаюсь, что Саттер строго доказал, что таких ситуаций нет.

Кроме того, меня по-прежнему будут волновать аксиомы интерфейса. Я вполне могу написать в Derived классе свой метод hello, который будет успешно работать для подалгебры Derived и не удовлетворять аксиомам Base, если не буду знать аксиом Base. То есть, NVI не может меня избавить от необходимости подробно втыкать в открытый интерфейс.

Итог: вместо того, чтобы втыкать только в открытый интерфейс, как с обычным наследованием, я должен ещё и разобрать защищённый.
Yandex
Объявления
07.11.2015, 13:56     Наследование - вызов конструкторов и деструкторов
Ответ Создать тему
Опции темы

Текущее время: 08:41. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru