繁体   English   中英

虚函数行为异常

[英]Strange behavior with virtual functions

使用以下代码,我希望输出为Bf Bf DD.f,但是我得到的输出为Bf Bf Bf当DD从具有f为虚数的D派生时,这怎么可能。

class B
{
public:
    void f() { cout << "B.f "; }
};

class D : public B
{
public:
    virtual void f() { cout << "D.f "; }
};

class DD : public D{
public:
    virtual void f() { cout << "DD.f "; }
};

B * b = new B();
B * d = new D();
B * dd = new DD();

b->f();
d->f();
dd->f();

函数从被声明为virtual的级别开始变为virtual 您首先在D声明f virtual ,这意味着动态分配将仅从D向上进行。 B没有,也不应该知道派生类。

考虑一下编译器如何看待它:

您有一个指向B的指针B具有以下定义:

class B
{
public:
    void f() { cout << "B.f "; }
};

由于f不是virtual ,所以我将继续静态解决该调用-即B::f()

为了使动态分配从指向B的指针开始工作,您需要在B中将f()虚拟化:

class B
{
public:
    virtual void f() { cout << "B.f "; }
};

您需要将B::f()设置为虚拟,而不将B::f()为虚拟,它不会出现在B虚拟表(vtbl)中,因此调用B::f()而不是调度调用派生类。

class B
{
public:
   virtual void f() { cout << "B.f "; }
};

在B中将f()声明为虚拟后,这便开始维护一个虚拟表,该表包含具有相同名称的派生类的所有其他函数的函数指针。 这是一个查找表,用于以动态/后期绑定方式解析函数调用。

当您使用引用或指针来调用方法时,编译器会在该方法的声明中搜索指针或引用的类型(此处,它在B搜索带有签名f()的某个方法的声明)。 当找到一个:

  • 如果未将其标记为virtual ,则将其解决为对该类定义的方法的调用-这是静态绑定。
  • 如果将其标记为virtual ,则调用的方法将是所引用或指向的对象中的合适对象之一-这是动态绑定。

下一个测试应该是:

DD * dd = new DD();
D * d = dd;
B * b = d;

b->f();
d->f();
dd->f();

一个单独的对象new DD()的使用/查看方式有所不同...每种类型都可以认为是您对对象的一种查看。 如果将其视为Bf()执行某些操作,但始终是相同的,但是如果将其视为DDD ,则f()执行不同的操作...

如果您在街上遇到某人,向他致敬的标准方法是打个招呼,但对于同一个人,当他遇到他的一个朋友时,他要么打个招呼! 或哟!

class Person {
public:
  void salute() { cout << "Hello" << endl; }
};
class Friend : public Person {
public:
  virtual void salute() { cout << "Hi!" << endl; }
};
class RoomMate : public Friend {
public:
  virtual void salute() { cout << "Yo!" << endl; }
};
void asACustomer(Person &p) {
   p.salute(); // static binding, we need the standard politeness
}
void asAFriend(Friend &f) {
    p.salute(); // dynamic binding, we want an appropriate message...
}
RoomMate joe;
asCustomer(joe);
asFriend(joe);

使用静态绑定,您可以在编译时知道调用哪个方法。 使用动态绑定,您将无法做到,只知道合适的绑定就可以了。 这是子类型多态性的关键点。

通常,将静态绑定和动态绑定混合用于方法时要小心。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM