Вот фрагмент кода, который я написал, чтобы увидеть поведение во время даункинга.
#include <iostream>
using namespace std;
class base {
public :
void function()
{
cout << "\nInside class Base";
}
};
class derived : public base {
public :
void function()
{
cout << "\nInside class Derived.";
}
};
int main()
{
base * b1 = new base();
base * b2 = new derived();
derived * b3 = (derived*)b1 ;
b1 -> function();
b2 -> function();
b3 -> function(); // print statement 3
static_cast<derived*>(b2) -> function();
static_cast<derived*>(b1) -> function(); // print statement 5
return 0;
}
Вывод следующий.
Inside class Base
Inside class Base
Inside class Derived.
Inside class Derived.
Inside class Derived.
Я чувствую, что оператор print 3 и оператор print 5 должны были отображать «Внутри базы классов».
Может кто-нибудь объяснить, что мне здесь не хватает?
Оба случая неопределенного поведения. Кастинг b1
в derived*
не является действительным.
Однако, если вы сказали base* b1 = new derived()
, вы бы имели такое же поведение. Поскольку ни одна функция не помечена virtual
затем проверяется только тип объектов во время компиляции.
Таким образом, в первом случае будет напечатано «Внутри класса Base», даже если это фактически производный указатель.
Вам нужно определить базовый метод void function()
как virtual
:
virtual void function()
{
cout << "\nInside class Base";
}
и в результате получается:
Inside class Base
Inside class Derived.
Inside class Base
Inside class Derived.
Inside class Base
В OP, 5-й случай не может быть неопределенным поведением, как указано в ссылке1 и встроенная память функции-члена не хранится как члены данных, как указано Вот гарантируя, что после статического приведения к производному типу, вызывается функция-член:
Инверсия любой стандартной последовательности преобразования (раздел 4) не
содержащий lvalue-to-rvalue (4.1), массив-указатель (4.2),
функция-указатель (4.3), нулевой указатель (4.10), нулевой указатель на член
(4.11), или логическое (4.12) преобразование, может быть выполнено явно
используя static_cast.
1 Рабочий проект, Стандарт для языка программирования C ++, 5.2.9 Static Cast — 7
Функции отправляются во время компиляции, основываясь исключительно на статическом типе, поскольку они не являются виртуальными.
Статический тип b3 в операторе печати — Derived *, следовательно, «Внутри класса Derived». Оператор печати 5 переводит Base * в Derived *, следовательно, та же распечатка.
Добавьте виртуальное определение функции () в Base и еще раз проверьте, что происходит.
Это ожидаемое поведение.
Не виртуальные методы вызываются типом объекта в время компиляции.
Вы использовали статическое приведение, поэтому компилятор обрабатывает его как класс «Derived».
Если бы вы объявили метод как virtual
затем он создаст виртуальную справочную таблицу для функции и вызовет метод в соответствии с фактическим время выполнения тип.