Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
rikimaru2013
2515 / 1177 / 355
Регистрация: 30.11.2013
Сообщений: 3,790
1

Вызов виртуального метода в конструкторе

07.10.2015, 18:20. Просмотров 1144. Ответов 12
Метки нет (Все метки)

Помню расматривался этот вопрос на форуме - хочу освежить память почему при вызове виртуального метода внутри конструктора UB
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.10.2015, 18:20
Ответы с готовыми решениями:

Вызов виртуального метода при создании
Добрый вечер, библиотека навязала следующее поведение: - объект создан и валиден, если...

Вызов виртуального метода класса наследника из вектора
#include <iostream> #include <vector> using namespace std; class A { public: ...

Вызов виртуального метода базового класса из указателя производного
Допустим есть такой код: #include <iostream> class Base { public: virtual void f() {...

Переопределение виртуального метода
Нужно написать виртуальный метод в родительском классе , который находит площадь круга. Затем...

Реализация виртуального метода в двух классах-наследниках
Здравствуйте! Есть три класса, абстрактный CGraphicsObject, и два его наследника Circle и...

12
Redzep
197 / 133 / 88
Регистрация: 21.12.2014
Сообщений: 369
07.10.2015, 18:50 2
Ссылка по теме: http://www.e-reading.club/chapter.ph...vanie_CPP.html
1
hoggy
Эксперт С++
7396 / 3320 / 686
Регистрация: 15.11.2014
Сообщений: 7,600
Завершенные тесты: 1
07.10.2015, 19:39 3
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
почему при вызове виртуального метода внутри конструктора UB
я конечно может быть ошибаюсь, но вроде бы нет никакого UB.

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

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


а поскольку нельзя запустить метод того, чего ещё не существует,
то при вызове виртуальной функции-члена,
происходит вызов функции-члена этого же класса,
а не класса наследника.

этот фактор создает иллюзию, что якобы на период действия конструктора,
полиморфизм вообще не работает.

на самом деле работает.
просто наследника ещё не существует,
и поэтому скрытый указатель на таблицу виртуальных фуункций
настроен на базовый класс, а не на класс наследника.
1
rikimaru2013
2515 / 1177 / 355
Регистрация: 30.11.2013
Сообщений: 3,790
07.10.2015, 19:49  [ТС] 4
Цитата Сообщение от hoggy Посмотреть сообщение
я конечно может быть ошибаюсь, но вроде бы нет никакого UB
так я в ступоре из-за этого. Вот есть проблески, что при каких-то действиях возможет вызов виртуального метода без реализации, что приведёт к UB - следовательно всю механику обозначили как UB.

Или я путаю с чем-то ... (
0
07.10.2015, 19:49
Croessmah
++Ͻ
15816 / 8951 / 1719
Регистрация: 27.09.2012
Сообщений: 21,994
Записей в блоге: 2
Завершенные тесты: 2
07.10.2015, 19:53 5
Лучший ответ Сообщение было отмечено rikimaru2013 как решение

Решение

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Вот есть проблески, что при каких-то действиях возможет вызов виртуального метода без реализации, что приведёт к UB - следовательно всю механику обозначили как UB.
10.4
6. Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.
1
OstapBender
587 / 525 / 76
Регистрация: 22.03.2011
Сообщений: 1,585
07.10.2015, 19:53 6
по-моему там работает простое правило: вируальный метод вызываемый в конструкторе трактуется как обычный (не виртуальный)
1
rikimaru2013
2515 / 1177 / 355
Регистрация: 30.11.2013
Сообщений: 3,790
07.10.2015, 20:01  [ТС] 7
При вызове деструктора
C++
1
A* ptr = new C(); delete ptr; // при C -> B- > A
Вызовется
C++
1
2
3
4
ptr->_(*(_vfptr + смещение_до_деструктора));
// тот в свою очередь вызовет 
B::~B(); 
A::~A();
Разве вызывая виртуальный метод в деструкторе ~B::, мы не имеет на момент вызова __vfptr значение указателя с указанием на адресс таблици класса С, которая будет вызывать свои методы переопределённые: в которых возможно обращение к полям которых уже нету (так как ~C:: отработал)
0
hoggy
Эксперт С++
7396 / 3320 / 686
Регистрация: 15.11.2014
Сообщений: 7,600
Завершенные тесты: 1
07.10.2015, 20:09 8
Лучший ответ Сообщение было отмечено rikimaru2013 как решение

Решение

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
следовательно всю механику обозначили как UB.
если так, тогда весь полиморф можно назвать одним большим UB.
потому что вызвать чисто-виртульную функцию без туловища - как нефиг нафиг.

кстати, обратите внимание:
Цитата Сообщение от hoggy Посмотреть сообщение
этот фактор создает иллюзию, что якобы на период действия конструктора,
полиморфизм вообще не работает.
Цитата Сообщение от OstapBender Посмотреть сообщение
о-моему там работает простое правило: вируальный метод вызываемый в конструкторе трактуется как обычный (не виртуальный)
Добавлено через 3 минуты
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
При вызове деструктора
аналогично с конструкторами:

первыми разрушаются потомки, потом предки.
когда отрабатывает диструктор потомка,
он перестает существовать.
и указатель на vtbl модифицируется,
указывая на ещё остающуюся в живых часть предка.

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

и как я уже писал выше - нельзя позвать то, чего не существует.
1
rikimaru2013
2515 / 1177 / 355
Регистрация: 30.11.2013
Сообщений: 3,790
07.10.2015, 20:11  [ТС] 9
Пока работает конструктор Base, инициализируя базовую часть объекта Derived, этот объект относится к типу Base. Именно так его воспринимают все части C++, и в этом есть смысл: части объекта, относящиеся к Derived, еще не инициализированы, поэтому безопаснее считать, что их не существует вовсе. Объект не является объектом производного класса до тех пор, пока не начнется исполнение конструктора последнего. То же относится и к деструкторам
Понравилась фраза
Объект не является объектом производного класса до тех пор, пока не начнется исполнение конструктора последнего. То же относится и к деструкторам
Если они верна - возьму на вооружение. Раставила все точки...


Цитата Сообщение от hoggy Посмотреть сообщение
когда отрабатывает диструктор потомка,
он перестает существовать.
и указатель на vtbl модифицируется
Спасибо, потому что гуглил __vfptr и на msdn кратко про него " ... инициализация происходит в контрукторе класса". Проверил VS2013 - в списке инициализации, если вызвать виртуальный метод и в самом конструкторе, то vfptr уже с новыми значениями. Тоесть при входе в список инициализации класса B - он уже проиничен таблицей данного класса
0
hoggy
Эксперт С++
7396 / 3320 / 686
Регистрация: 15.11.2014
Сообщений: 7,600
Завершенные тесты: 1
07.10.2015, 20:24 10
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Понравилась фраза
только не "начнется", а "завершиться":

Объект не является объектом производного класса до тех пор,
пока не завершиться исполнение его конструктора
0
rikimaru2013
2515 / 1177 / 355
Регистрация: 30.11.2013
Сообщений: 3,790
07.10.2015, 20:30  [ТС] 11
Цитата Сообщение от hoggy Посмотреть сообщение
только не "начнется", а "завершиться":
тогда почему
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
 
class A
{
 
};
class B : public A
{
public:
    B()
    {
        cout << (dynamic_cast<B*>(this) != nullptr) << endl;
    }
};
 
int main()
{
    A* a = new B();
}
0
hoggy
Эксперт С++
7396 / 3320 / 686
Регистрация: 15.11.2014
Сообщений: 7,600
Завершенные тесты: 1
07.10.2015, 20:36 12
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
тогда почему
потому что не гарантируется.
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7642 / 3791 / 518
Регистрация: 04.12.2011
Сообщений: 10,941
Записей в блоге: 5
07.10.2015, 20:58 13
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
cout << (dynamic_cast<B*>(this) != nullptr) << endl;
а кастить зачем?
http://www.cyberforum.ru/post4983727.html
0
07.10.2015, 20:58
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.10.2015, 20:58

Автоматический вызов функций в конструкторе
В общем друзья, надо разобраться как можно в конструкторе объекта класса, автоматически вызывать...

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

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


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

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

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