Я наткнулся на какое-то странное поведение, экспериментируя с dynamic_cast. Это код, который я имею
struct Base
{
virtual ~Base(){}
virtual void output() = 0;
};
struct Derived1 : public Base
{
void output() {}
void doDerived_1()
{
std::cout << "derived 1\n";
}
};
struct Derived2: public Base
{
void output() {}
void doDerived_2()
{
std::cout << "derived 2\n";
}
};
int main()
{
Base* base = new Derived1();
Derived2* der2 = dynamic_cast<Derived2*>(base);
// der2 = 0
der2->doDerived_2();
}
Хотя der2 равно 0, doDerived_2() все равно будет вызываться, и любой код внутри него будет выполнен. Кодекс ломается, когда я вызываю функцию output().
Может кто-нибудь объяснить мне, почему это работает и не ломается, когда это ясно? благодаря
Ваш код имеет неопределенное поведение, потому что вы разыскиваете нулевой указатель.
Тем не менее, возможная реализация для вызова функции-члена осуществляется через соглашение вызова thiscall, которое неявно передает указатель объекта в качестве первого параметра. Если ваша функция не имеет доступа к каким-либо переменным-членам, this
указатель не разыменован, и функция может выполняться так, как ожидалось. Это не имеет ничего общего с dynamic_cast.
Обратите внимание, что это не гарантируется в стандарте
Пример:
struct Foo {
int doIt() {return 42;}
};
int main() {
Foo *f = NULL;
std::cout << f->doIt();
}
Печать 42 на некоторых компиляторах
Вы разыскиваете нулевой указатель. Поведение такой операции не определено. В этом случае происходит вызов метода, при this
он является нулевым указателем. Однако все может случиться.
Если вы хотите, чтобы исключение было выбрано вместо этого, введите ссылки:
Derived2& der2 = dynamic_cast<Derived2&>(*base);
der2.doDerived_2();
В качестве альтернативы вы можете использовать if-statement для выполнения некоторого кода только в том случае, если листинг преуспевает:
if (Derived2* der2 = dynamic_cast<Derived2*>(base)) {
der2->doDerived_2();
}
nullptr
!