Я изучаю виртуальные функции, и я очень запутался с результатами нижеприведенной программы
Я надеялся, что оба a1.virFun(b1)
а также b1.virFun(b1)
должен вернуть «привет от B», но программа возвращает «привет от A». Это противоречит моему пониманию. Можете ли вы объяснить, почему b1.sayHello()
не вызывается, даже когда я передаю b1 в качестве аргумента и b1.sayHello()
это виртуальная функция.
#include<iostream>
using namespace std;
class A
{
public:
virtual void sayHello();
void virFun(A obj);
};
class B : public A
{
public:
void virFun(A obj);
virtual void sayHello();
};
void A::sayHello()
{
cout << "hello from A" << endl;
}
void B::sayHello()
{
cout <<"hello from B" << endl;
}
void A::virFun(A obj)
{
obj.sayHello();
}
void B::virFun(A obj)
{
obj.sayHello();
}
int main()
{
A a1;
B b1;
a1.virFun(b1);
b1.virFun(b1);
return 0;
}
Заставьте virFun брать ссылку, а не объект по значению:
void A::virFun(A& obj) { obj.sayHello(); }
причина: Если вы берете
A
по значению, параметр будет инициализирован путем создания копии переданного значения. Если вы передадите B, он скопирует часть «A» в новую переменную типа параметра (A
) — это известно как нарезка объектов. Параметр больше не будет «be-a»B
например, он будет вести себя какA
Например, хорошо.
Нет необходимости переопределять virFun в классе B, так как он использует аргумент obj в обоих случаях
На самом деле virFun может быть статической функцией. Название сбивает с толку, так как это даже не virFun (виртуальная функция) — это обычная функция, которая использования виртуальная функция.
#include<iostream>
using namespace std;
struct A { virtual void sayHello() { cout << "hello from A" << endl; } };
struct B : A { /*virtual*/ void sayHello() { cout << "hello from B" << endl; } };
static void virFun(A& obj)
{
obj.sayHello();
}
int main()
{
A a1;
B b1;
virFun(a1);
virFun(b1);
}
Смотрите это в прямом эфире http://liveworkspace.org/code/1624496ced29eb4683f5b19072f72f60
hello from A
hello from B
void virFun(A obj);
Чтобы виртуальные функции работали, вам нужно передавать объекты по ссылке или по указателю, чтобы вы всегда работали с исходным объектом.
void virFun(const A &obj);
void virFun(const A *obj);
Иначе virFun()
получит копия вашего объекта, который заканчивается «Нарезка» это и потеря информации производного класса. Копия имеет A
vtable и отсутствует B
дополнительные поля. Обычно это катастрофа.
Как правило, передавайте объекты, используя T&
или же const T&
а не простой T
, Помимо проблемы нарезки, она также более эффективна.