15.5 继承中的类作用域
如果一个名字在派生类的作用域无法解析,则编译器将继续在外层的基类作用域中寻找该名字的定义
继承关系
Bulk_quote -> Disc_quote -> Quote
Bulk_quote bulk;
cout << bulk.isbn();
在Bulk_quote
中查找isbn
函数失败,没定义,所以往上找,Disc_quote
中也没有,再往上,在Quote
中找到了
静态类型决定了哪些成员是可见的
在Disc_quote
中定义了一个函数discount_policy
class Disc_quote {
pair<size_t, double> discount_policy() const {
return {quantity, discount};
}
};
Bulk_quote bulk;
Bulk_quote *bulkP = &bulk; // 静态类型与动态类型一致
Quote *itemP = &bulk; // 静态类型与动态类型不一致
bulkP->discount_policy(); // 正确
itemP->discount_policy(); // 错误
bulkP
的静态类型是Bulk_quote
,调用discount_policy
时,先在Bulk_quote
中找,没找到,就往上,在Disc_quote
中找到,调用成功
itemP
的静态类型是Quote
,调用discount_policy
时,在Quote
中找没找到,往上已经没有了,所以调用失败
派生类的成员将隐藏同名的基类成员
struct Base {
Base(): mem(0) {} // Base::mem进行默认初始化
protected:
int mem;
};
struct Derived: Base {
Derive(int i): mem(i) {} // 用i初始化Derived::mem
int get_mem() { return mem; }
protected:
int mem; // 隐藏基类中的mem
};
struct Base {
int memfcn();
};
struct Derived: Base {
int memfcn(int); // 隐藏了基类的memfcn
};
Base b;
Derived d;
b.memfcn(); // 调用Base::memfcn
d.memfcn(10); // 调用Derived::memfcn
d.memfcn(); // 错误,基类的memfcn被隐藏了无法调用
d.Base::memfcn(); // 显式地说明要调用基类的memfcn
虚函数与作用域
struct Base {
public:
virtual int fcn();
};
class D1: public Base {
public:
// 继承了Base::fcn的定义,没有override
int fcn(int); // 隐藏了基类的fcn,不是虚函数
virtual void f2(); // 声明了一个虚函数
};
struct D2: public D1 {
int fcn(int); // 不是虚函数,隐藏了D1::fcn(int)
int fcn(); // override Base::fcn()
void f2(); // override D1::f2()
};
Base bobj;
D1 d1obj;
D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->fcn(); // 调用Base::fcn()
bp2->fcn(); // 调用Base::fcn()
bp3->fcn(); // 调用D2::fcn()
bp2
的静态类型是Base
,动态类型是D1
,调用fcn
时,因为D1
没有覆盖Base
的fcn
,所以还是调用Base
的fcn
bp3
的静态类型是Base
,动态类型是D2
, 调用fcn
时,因为D2
有覆盖Base
的fcn
,所以调用D2
版本的fcn
D1 *d1p = &d1obj;
D2 *d2p = &d2obj;
bp2->f2(); // 错误,Base中没有f2,调用失败,静态类型决定接口
d1p->f2(); // 正确,调用D1::f2()
d2p->d2(); // 正确,调用D2::f2()
bp2
的静态类型是Base
,调用f2
时,在Base
中没找到f2
,所以调用失败d1p
的静态类型和动态类型是D1
,调用f2
时,在D1
中找到了f2
,所以调用D1::f2
d2p
的静态类型和动态类型是D2
,调用f2
时,在D2
中找到了f2
,所以调用D2::f2
Base *p1 = &d2obj; // 静态类型Base,动态类型D2
D1 *p2 = &d2obj; // 静态类型D1,动态类型D2
D2 *p3 = &d2obj; // 静态类型D2,动态类型D2
p1->fcn(42); // 错误,静态类型Base中没有fcn(int)
p2->fcn(42); // 静态绑定,非虚函数,调用D1::fcn(int)
p3->fcn(42); // 静态绑定,非虚函数,调用D2::fcn(int)