Меня смутило преобразование указателя на объект базового класса в указатель производного класса.
Пожалуйста, проверьте следующий код:
derivate_class *d1 = (derivate_class*)cb;
d1->print();
d1->print1();
Результат:
Может кто-нибудь помочь мне объяснить, почему d1->print()
print «Я виртуальная функция в базе.»
#include <iostream>
using namespace std;
class base
{
public:
virtual void print()
{
cout << "I'm a virtual function in base." << endl;
}
};
class derivate_class : public base
{
public:
void print()
{
cout << "I rewrite the virtual function in base." << endl;
}
void print1()
{
cout << "I'm a function in derivate class." << endl;
}
};
int main()
{
base* b = new base();
derivate_class *d = new derivate_class();
b->print();
d->print1();
base* cb = b;
b = d;
b->print();
cout << "*********************" << endl;
derivate_class *d1 = (derivate_class*)cb;
d1->print();
d1->print1();
system("pause");
return 0;
}
Это UB, так что все может случиться.
Но вот объяснение: d1
на самом деле не указывает на derivate_class
, но к base
,
base* b = new base();
//...
base* cb = b;
derivate_class *d1 = (derivate_class*)cb;
d1->print();
d1->print1();
Вызов разрешается динамически, потому что это через указатель и метод virtual
,
print1
не virtual
поэтому вызов разрешается статически. print
однако virtual
, поэтому реализация в наиболее производном типе называется. Но самый производный тип на самом деле base
в этом случае.
Под капотом, метод print
ищется в таблице виртуальных функций, в которой vfptr cb
указывает на. поскольку cv
это base
стол будет из base
, который содержит функцию print
с base::print
реализация. Вот почему эта функция вызывается.
d1 является указателем производного_класса, но данные, на которые он фактически указывает (cb), имеют тип base. Поскольку print () является виртуальным, вызов разрешается динамически, и поэтому он найдет реализацию базы в таблице виртуальных функций, а не в производном_классе.