Afzaal Ahmad Zeeshan
О боже, у тебя там все перепутано с полиморфизмом и безопасностью типов. То, что вы ожидаете, происходит неправильно, это не то, почему тип наследуется. Наследование работает от родителя к ребенку. Таким образом, функция в родителе гарантирована—давайте на минуту проигнорируем модификаторы доступа в наследовании—в детском типе, но не наоборот. Вы не можете вызвать дочернюю функцию из родительского типа. Родительский тип просто не знает, что это за функция. Так,
class Foo {
int a;
int b;
};
class Bar {
string name;
};
В приведенном выше коде вы можете сделать это,
Bar b;
cout << b.a; // a comes from Foo
Но вы не можете этого сделать,
Foo f;
cout << f.name; // name does not exist
Но в наследовании полиморфизм работает просто отлично. Итак, в вашем коде, если мы сделаем это,
class deri : public base
{
public:
int func_1() override // <-- let's override, since base has it virtual
{
cout << "Derived func_1";
return 0; // <-- Why did you forget this and didn't complain?
}
Теперь, когда вы запускаете тот же код,
base* base = new deri;
base->func_1();
Он будет печатать: "производная функция func_1". Почему? Из-за полиморфизма.
Я не хочу посвящать вас в детали модели памяти C++, потому что все эти детали применяются там. Просто помните, что наследование работает от родителя к потомку, но полиморфизм заставляет вызовы функций выполняться на фактическом типе экземпляра—в вашем случае
new deri;
.
Пожалуйста, смотрите ссылки ниже, чтобы узнать немного больше об этой концепции,
Полиморфизм (информатика) - Википедия[
^]
Тип безопасности - Википедия[
^]
Модель памяти - cppreference.com[
^]
c++ - как на самом деле работает наследование? - переполнение стека[
^]
Дружба и наследование - учебники по C++ [
^]
Member 13913102
thx для вашего подробного объяснения, я снова пройдусь по вашему ответу, у меня все еще есть несколько сомнений.
Если в базовом классе я переименую func_1 в func_2, то это будет работать нормально, и функция производного класса будет вызвана, как это делают концепции __vtable и __vptr. __vptr будет иметь адрес __vtable производного класса.
Но прежде чем переименовать func_1 в func_2(в исходном коде), почему __vptr не смог найти виртуальный func_2
vtable объяснение, которое я узнал, находится здесь:
http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/
Afzaal Ahmad Zeeshan
Если в базовом классе я переименую func_1 в func_2, то это будет работать нормально и будет вызвана функция производного класса
Нет, но потому, что теперь базовый тип будет иметь func_2, а не func_1. В этом случае, если вы попытаетесь вызвать func_1 на базе, он выдаст ту же ошибку.
Я не совсем понимаю, что вы подразумеваете под последним предложением в первом абзаце. Виртуальная таблица создается для типа, который создается, как и в вашем случае, это был производный тип. Таким образом, виртуальная таблица была создана для типа deri и заставила его знать функции. Но когда вы пытаетесь вызвать функцию func_2, базовый тип не имеет никакой информации об этом.
Помните, что виртуальная таблица существует во время выполнения. Эта ошибка возникает во время компиляции, поэтому концепция виртуальной таблицы еще не существует. При построении и выполнении программы ваша виртуальная таблица берет управление на себя, а модель памяти C++ заставляет программу принимать полиморфизм.