2542 / 1201 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
1

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

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

Помню расматривался этот вопрос на форуме - хочу освежить память почему при вызове виртуального метода внутри конструктора UB
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.10.2015, 18:20
Ответы с готовыми решениями:

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

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

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

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

12
201 / 137 / 88
Регистрация: 21.12.2014
Сообщений: 369
07.10.2015, 18:50 2
Ссылка по теме: http://www.e-reading.club/chap... e_CPP.html
1
Эксперт С++
8410 / 4085 / 892
Регистрация: 15.11.2014
Сообщений: 9,176
07.10.2015, 19:39 3
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
почему при вызове виртуального метода внутри конструктора UB
я конечно может быть ошибаюсь, но вроде бы нет никакого UB.

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

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


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

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

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

Или я путаю с чем-то ... (
0
Don't worry, be happy
17148 / 10031 / 1933
Регистрация: 27.09.2012
Сообщений: 24,970
Записей в блоге: 1
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
592 / 530 / 76
Регистрация: 22.03.2011
Сообщений: 1,585
07.10.2015, 19:53 6
по-моему там работает простое правило: вируальный метод вызываемый в конструкторе трактуется как обычный (не виртуальный)
1
2542 / 1201 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
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
Эксперт С++
8410 / 4085 / 892
Регистрация: 15.11.2014
Сообщений: 9,176
07.10.2015, 20:09 8
Лучший ответ Сообщение было отмечено rikimaru2013 как решение

Решение

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

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

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

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

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


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

Объект не является объектом производного класса до тех пор,
пока не завершиться исполнение его конструктора
0
2542 / 1201 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
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
Эксперт С++
8410 / 4085 / 892
Регистрация: 15.11.2014
Сообщений: 9,176
07.10.2015, 20:36 12
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
тогда почему
потому что не гарантируется.
0
Комп_Оратор)
Эксперт по математике/физике
8719 / 4426 / 598
Регистрация: 04.12.2011
Сообщений: 13,262
Записей в блоге: 16
07.10.2015, 20:58 13
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
cout << (dynamic_cast<B*>(this) != nullptr) << endl;
а кастить зачем?
https://www.cyberforum.ru/post4983727.html
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.10.2015, 20:58

Помощь в написании контрольных, курсовых и дипломных работ здесь.

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

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

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

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


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

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

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