当您使用引用或指针调用方法时,编译器会在方法的声明处搜索指针或引用的类型(这里它在B
带有签名的某些方法的声明中搜索f()
)。当它找到一个时:
- 如果它没有被标记为
virtual
,那么它将它作为对此类定义的方法的调用来解决 - 这是一个静态绑定。
- 如果它被标记为
virtual
,则调用的方法将是引用或指向的对象的适当之一 - 这是一个动态绑定。
下一个测试是:
DD * dd = new DD();
D * d = dd;
B * b = d;
b->f();
d->f();
dd->f();
一个使用/查看方式不同的单个对象new DD()
...每种类型都可以被视为您对对象的一种视图。如果您将其视为 aB
则f()
做某事,但总是做同样的事情,但如果您将其视为D
or DD
,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);
使用静态绑定,您在编译时就知道调用了哪个方法;使用动态绑定你不能,你只知道一个合适的绑定。这是子类型多态性的一个关键点。
通常,在为方法混合静态和动态绑定时要小心。