3

我正在学习虚函数,我对以下程序的结果感到非常困惑,我希望两者都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;
}
4

2 回答 2

6
void virFun(A obj);

要使虚函数工作,您需要通过引用或指针传递对象,以确保您始终使用原始对象。

void virFun(const A &obj);
void virFun(const A *obj);

否则virFun()将收到您的对象的副本,最终“切片”它并丢失派生类的信息。该副本具有A' 的 vtable 并且缺少B' 的额外字段。这通常是一场灾难。

作为一般规则,使用T&orconst T&而不是 plain传递对象T。除了切片问题,它也更有效。

于 2012-10-12T13:46:04.687 回答
3

让 virFun 按值获取引用,而不是 A 对象:

 void A::virFun(A& obj) { obj.sayHello(); }

原因:如果你A取值,参数将通过复制传递的值来初始化。如果您传递一个 B,它会将其中的“A”部分复制到参数类型 ( A) 的新变量中 - 这称为对象切片。该参数将不再“成为”B实例,因此它将表现为一个A实例,好吧。

无需重写 B 类中的 virFun,因为它在两种情况下都使用参数 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
于 2012-10-12T13:45:32.987 回答