наследование — неправильное поведение при понижении стека переполнения

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

#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 должны были отображать «Внутри базы классов».

Может кто-нибудь объяснить, что мне здесь не хватает?

0

Решение

Оба случая неопределенного поведения. Кастинг b1 в derived* не является действительным.

Однако, если вы сказали base* b1 = new derived(), вы бы имели такое же поведение. Поскольку ни одна функция не помечена virtualзатем проверяется только тип объектов во время компиляции.

Таким образом, в первом случае будет напечатано «Внутри класса Base», даже если это фактически производный указатель.

5

Другие решения

Вам нужно определить базовый метод 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

1

Функции отправляются во время компиляции, основываясь исключительно на статическом типе, поскольку они не являются виртуальными.

Статический тип b3 в операторе печати — Derived *, следовательно, «Внутри класса Derived». Оператор печати 5 переводит Base * в Derived *, следовательно, та же распечатка.

Добавьте виртуальное определение функции () в Base и еще раз проверьте, что происходит.

0

Это ожидаемое поведение.
Не виртуальные методы вызываются типом объекта в время компиляции.
Вы использовали статическое приведение, поэтому компилятор обрабатывает его как класс «Derived».

Если бы вы объявили метод как virtual затем он создаст виртуальную справочную таблицу для функции и вызовет метод в соответствии с фактическим время выполнения тип.

-1
По вопросам рекламы [email protected]