c ++虚函数混淆

时间:2012-10-12 13:43:10

标签: c++ inheritance virtual-functions

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

2 个答案:

答案 0 :(得分:6)

void virFun(A obj);

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

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

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

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

答案 1 :(得分:3)

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

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

原因:如果按值A取值,则会通过复制传递的值来初始化参数。如果您通过B,它将复制&#39; A&#39;将其中的一部分转换为参数类型(A)的新变量 - 这称为 object slicing 。该参数将不再是&#39; be-a&#39; 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