1

使用以下代码,我希望输出是 Bf Bf DD.f,但我得到的输出是 Bf Bf Bf 这怎么可能,当DD派生自Dwhich has fas virtual 时。

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();
4

5 回答 5

4

函数virtual从它们被声明的级别virtual开始。您首先声明f virtualin D,这意味着动态调度只会从D向上发生。B不,也不应该知道派生类。

想想编译器如何看待它:

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

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

既然f不是virtual,我将继续静态地解决呼叫 - 即B::f()

于 2013-01-28T12:11:09.137 回答
2

要使动态调度从指向 的指针工作B,您需要使f()virtual in B

class B
{
public:
    virtual void f() { cout << "B.f "; }
};
于 2013-01-28T12:09:39.927 回答
1

您需要设置B::f()为virtual,不设置B::f()为virtual,它不会出现在B virtual table(vtbl)中,因此B::f()被调用而不是派生调用派生类。

class B
{
public:
   virtual void f() { cout << "B.f "; }
};
于 2013-01-28T12:09:50.650 回答
0

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

于 2013-01-28T12:29:31.303 回答
0

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

  • 如果它没有被标记为virtual,那么它将它作为对此类定义的方法的调用来解决 - 这是一个静态绑定。
  • 如果它被标记为virtual,则调用的方法将是引用或指向的对象的适当之一 - 这是一个动态绑定。

下一个测试是:

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

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

一个使用/查看方式不同的单个对象new DD()...每种类型都可以被视为您对对象的一种视图。如果您将其视为 aBf()做某事,但总是做同样的事情,但如果您将其视为Dor DDf()则做一些不同的事情...

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

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);

使用静态绑定,您在编译时就知道调用了哪个方法;使用动态绑定你不能,你只知道一个合适的绑定。这是子类型多态性的一个关键点。

通常,在为方法混合静态和动态绑定时要小心。

于 2013-01-28T18:32:57.933 回答