Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
m45
0 / 0 / 0
Регистрация: 06.07.2015
Сообщений: 24
1

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

01.11.2015, 02:04. Просмотров 1353. Ответов 53
Метки нет (Все метки)

Делаю два класса - предок и потомок:
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
Первый и третий случаи - все понятно.
Подскажите пожалуйста, почему во втором случае не вызвался деструктор класса-наследника??
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.11.2015, 02:04
Ответы с готовыми решениями:

Вызов конструкторов/деструкторов при наследовании
Объясните пожалуйста, как получается вывод на экран 2531 #include &lt;iostream&gt;...

Вызов лишних конструкторов и деструкторов в std::vector
почему вызывает лишние конструкторы и вообще делает не то, что ожидаешь class...

Порядок вызова конструкторов/деструкторов
Вопрос чисто теоретический. Попробую сформулировать, не ругайте если получится...

Правильное использование конструкторов и деструкторов
#include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace...

Задание с использованием конструкторов и деструкторов
Нужна ваша помощь. Само задание: Разработать класс - СТУДЕНТ. В закрытой...

53
mporro
306 / 101 / 18
Регистрация: 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.
0
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
05.11.2015, 14:55 22
Цитата Сообщение от m45 Посмотреть сообщение
Так а почему для конструктора не нужно указывать метод виртуальным?
Потому, что пока не построен объект для него не существует таблицы виртуальных функций. Нельзя выбрать тип конструктора не имея объекта от имени которого эта функция будет вызывается. Виртуальные деструкторы конечно отличаются от простых методов однако ж они вызываются для уже существующих объектов.
0
gromo
372 / 271 / 30
Регистрация: 04.09.2009
Сообщений: 1,214
05.11.2015, 14:59 23
mporro, метода private_hello не может не быть, ибо он объявлен в самом базовом классе.
И почему у вас в Derived переопределение чисто виртуальной функции в чисто виртуальную?!
0
mporro
306 / 101 / 18
Регистрация: 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 много ограничений и недостатков, а преимуществ очень мало.
Их следует использовать только в специфических ситуациях, но никак не с такими претензиями, как рекламировал Саттер.
0
gromo
372 / 271 / 30
Регистрация: 04.09.2009
Сообщений: 1,214
05.11.2015, 15:51 25
mporro, так ведь невиртуальный метод hello, как раз и предназначен, чтобы скрыть это. В нем проверяем все предусловия, инварианты и постусловия. Если на то пошло, то можно в самом базовом классе сделать безобидную заглушку для impl-метода (например, сделать его пустым), которая избавит вас от необходимости делать его пустым в своем подклассе, тобишь "вдаваться в детали".
0
mporro
306 / 101 / 18
Регистрация: 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 говорит что-то про отношение является между реализацией, которая использует методы и реализацией, которая эти методы поставляет.
0
hoggy
Нарушитель
Эксперт С++
7087 / 3130 / 648
Регистрация: 15.11.2014
Сообщений: 7,209
Завершенные тесты: 1
07.11.2015, 11:35 27
Цитата Сообщение от mporro Посмотреть сообщение
то теперь к ним ещё прилипнут контракты приватных методов.
противоречие здравому смыслу,
и самой причине существования модификатора доступа private

Добавлено через 1 минуту
Цитата Сообщение от mporro Посмотреть сообщение
и ещё на приватные методы смотреть.
не нужно.
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 11:47 28
Цитата Сообщение от hoggy Посмотреть сообщение
не нужно.
Как обычно, только в Ваших фантазиях.
Обсуждать их не имеет смысла.
0
hoggy
Нарушитель
Эксперт С++
7087 / 3130 / 648
Регистрация: 15.11.2014
Сообщений: 7,209
Завершенные тесты: 1
07.11.2015, 11:52 29
Цитата Сообщение от mporro Посмотреть сообщение
Как обычно, только в Ваших фантазиях.
вам часто приходится втыкать в приватные секции библиотечных классов?
скорее всего вы даже не подозреваете об их существовании.
но это не мешает вам продуктивно с ними работать.

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

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

и кстати, у вас там выше собственность предназначенная для наследников помечена как private
а должна быть protected.
косяк в дизайне и печалька.
0
gromo
372 / 271 / 30
Регистрация: 04.09.2009
Сообщений: 1,214
07.11.2015, 12:06 30
Цитата Сообщение от hoggy Посмотреть сообщение
у вас там выше собственность предназначенная для наследников помечена как private
а должна быть protected.
Где именно ?
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 12:22 31
Цитата Сообщение от hoggy Посмотреть сообщение
так и должно быть с грамотно сконструированным кодом.
Прочитайте статью Саттера.
Там чёрным по белому написано keep virtual functions private.
Вся суть NVI в том, что Вы перегружаете не открытый контракт, а закрытый.
А вот чтобы перегружать закрытый контракт, Вам придётся в него "втыкать".
0
hoggy
Нарушитель
Эксперт С++
7087 / 3130 / 648
Регистрация: 15.11.2014
Сообщений: 7,209
Завершенные тесты: 1
07.11.2015, 12:47 32
Цитата Сообщение от gromo Посмотреть сообщение
Где именно ?
Цитата Сообщение от mporro Посмотреть сообщение
private:
* * virtual void private_hello(std::ostream&) =0;
частная собственность класса наследников не должна касаться.
имя функции-члена тоже доставляет:
"переопределяйте детали реализации"
0
gromo
372 / 271 / 30
Регистрация: 04.09.2009
Сообщений: 1,214
07.11.2015, 12:49 33
Цитата Сообщение от hoggy Посмотреть сообщение
имя функции-члена тоже доставляет:
"переопределяйте детали реализации"
Прочитайте стать Virtuality Саттера.

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

Еще часто применяют префикс `do_`. Публичная интерфейсная функция request(), рабочая функция — do_request(), что я нахожу более привлекательным нежели `private_`, но кому как нравится
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 12:51 34
hoggy
Сначала, пожалуйста, ознакомьтесь со статьёй Саттера.
Только после этого отвечайте по теме NVI.
Вопросы, которые Вы пытаетесь адресовать мне, следует адресовать Саттеру.
0
hoggy
Нарушитель
Эксперт С++
7087 / 3130 / 648
Регистрация: 15.11.2014
Сообщений: 7,209
Завершенные тесты: 1
07.11.2015, 13:02 35
Цитата Сообщение от mporro Посмотреть сообщение
Там чёрным по белому написано keep virtual functions private.
это может быть нужно только и только,
если существует объективная причина не позволить наследнику
выполнить прямой вызов виртуальной функции базового класса,

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

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

только с толку сбивают.
потому что protected - это то, что доктор прописал специально для наследников.
а private - частная собственность.
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 13:04 36
hoggy
Мне то зачем это рассказывать?
Расскажите это Саттеру.
0
hoggy
Нарушитель
Эксперт С++
7087 / 3130 / 648
Регистрация: 15.11.2014
Сообщений: 7,209
Завершенные тесты: 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).

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

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

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

Замена private на protected не решает проблемы лишней детали.
0
hoggy
Нарушитель
Эксперт С++
7087 / 3130 / 648
Регистрация: 15.11.2014
Сообщений: 7,209
Завершенные тесты: 1
07.11.2015, 13:36 39
Цитата Сообщение от mporro Посмотреть сообщение
втыкать придётся не только в открытый контракт
только прототип.
реализация его не интересует.

Цитата Сообщение от mporro Посмотреть сообщение
в защищённый (protected) контракт, который тоже нужно соблюдать.
разумеется. он для того и существует,
что бы разработчик наследника в него втыкал,
и соблюдал.
Цитата Сообщение от mporro Посмотреть сообщение
Зачем мне нужна эта лишняя деталь защищённого контракта?
странный вопрос.
что бы корректно унаследоваться и породить наследника.
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
07.11.2015, 13:56 40
Цитата Сообщение от hoggy Посмотреть сообщение
что бы корректно унаследоваться и породить наследника
Чтобы корректно унаследоваться мне достаточно информации об открытом контракте, которая у меня уже есть.
Потому внедрение protected контракта -- это уже излишне. Зачем?

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

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

Итог: вместо того, чтобы втыкать только в открытый интерфейс, как с обычным наследованием, я должен ещё и разобрать защищённый.
0
07.11.2015, 13:56
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.11.2015, 13:56

Разработка классов, создание конструкторов и деструкторов
Здравствуйте, помогите решить следующее задание: Постpоить класс для pаботы...

Как реализовать набор конструкторов и деструкторов
Делаю так: #include &lt;iostream&gt; class Time //начало объявления класса {...

Ошибки в программе с использованием конструкторов/деструкторов
Приветы Есть код: #include &lt;iostream&gt; #include &lt;cmath&gt; #include...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru