类的关系图:

派生类的作用域嵌套在基类之内
Bulk_quote bulk;cout<< bulk.isbn();名字isbn解析过程:
成员名字的查找类型由静态类型决定
//给Disc_quote添加一个成员,返回折扣政策class Disc_quote : public Quote {public : std::pair<int ,double) discount_policy() const {return {quantity,discount};}};我们只能通过Disc_quote及其派生类对象来使用discount_policy。
Bulk_quote bulk;Bulk_qoute *bulkP = &bulk; //静态类型与动态类型一致Quote *itemP = &bulk; //静态类型为Quote,动态类型不一定bulkP->discount_policy(); //正确:bulkP的类型是Bulk_quote*itemP->discount_policy(); //错误:itemP的类型是Quote*尽管在bulk中确实含有一个名为discount_policy的成员,但是该成员对于itemP却是不可见的。
itemP的类型是Quote的指针,意味着对discount_policy的搜索将从Quote开始。
显然Quote不包含名为discount_policy的成员,所以我们无法通过Quote的对象、引用或指针调用discount_policy。
派生类可以重用基类中的名字,由于派生类的作用域嵌套在基类中,所以会隐藏基类的同名变量
派生类成员隐藏同名的基类成员
struct Base{ Base():mem(0){}protected: int mem;};struct Derived : Base{//struct默认public继承 Derived(int i) : mem(i){}; int get_mem() {return mem;}protected: int mem;};get_mem返回的是在Derived中的mem
Derived d(42);cout<<d.get_mem()<<endl; //打印42struct Derived : public Base{ int get_base_mem() {return Base::mem;} //...};d.get_base_mem(); //输出0| 派生类函数形式 | 与基类同名函数的关系 | 形参列表 | 绑定方式 |
|---|---|---|---|
| 非虚函数 | 隐藏基类同名函数 | 可相同可不同 | 静态绑定 |
| 虚函数 | 覆盖基类虚函数 | 必须相同 | 动态绑定 |
使用基类的引用或指针调用虚函数时,会发生动态绑定
//情况1举例class A{public : //基类的print不是虚函数 void print() const {cout<<"class A"<<endl;};};class B : public A{public: //B隐藏了A的同名函数 void print() const {cout<<"class B"<<endl;}};void Test_Print(const A &a){//传入基类的指针 //由于基类的print不是虚函数,所以不会动态绑定 //.print()的结果取决于a的静态类型 //所以无论传入的是A还是B,都打印class A a.print(); }int main(){ A a; B b; Test_Print(a); //打印class A Test_Print(b); //打印class A;因为传入参数的静态类型是A return 0;}当派生类有基类的同名函数且该函数是虚函数时
参数列表相同,实现覆盖基类虚函数,可以发生动态绑定
//情况2:参数列表相同时,虚函数被覆盖class A{public : //基类的print是虚函数 void print() const {cout<<"class A"<<endl;};};/*class B和Test_Print都不变*/int main(){ A a; B b; Test_Print(a); //打印class A Test_Print(b); //打印class B;因为发生了动态绑定 return 0;}参数列表不相同,相当于派生类定义了一个新函数,隐藏了基类虚函数,基类的虚函数没有被覆盖
class A{public : //基类的print是虚函数 void print() const {cout<<"class A"<<endl;};};class B : public A{public: //B的print(int i)与基类虚函数同名 //但参数列表不同,定义了一个新函数 //基类的虚函数print()没有被覆盖 void print(int i) const {cout<<"print(int i)"<<endl;}};void Test_Print(const A &a){//传入基类的指针 a.print(); }int main(){ A a; B b; //打印class A Test_Print(a); //打印class A; //因为派生类没有重载虚函数,继续调用基类虚函数 Test_Print(b); //打印print(int i) //调用派生类新增的函数print(int i) b.print(42); return 0;}例子出自《C++ Primer》P550
//类的定义class Base{public : virtual int fcn();};class D1 : public Base{public: //隐藏基类的fcn,这个fcn不是虚函数 //D1继承了Base::fcn()虚函数的定义 int fcn(int); //形参列表与Base中的fcn不一致 virtual void f2(); //定义一个新的虚函数,它在Base中不存在};class D2 : public D1{public : int fcn(int); //是一个非虚函数,隐藏了D1::fcn(int) int fcn(); //覆盖了虚函数Base::fcn() void f2(); //覆盖了虚函数f2};//调用虚函数的例子//fcn是Base中的虚函数//D1直接继承Base的虚函数fcn//D2重载了Base的fcnBase bobj;D1 d1obj;D2 d2obj;Base *bp1 = &bobj, *bp2 = &d1jobj, *bp3 = &d2obj;bp1->fcn(); //虚调用:运行时执行Base::fcnbp2->fcn(); //虚调用:运行时执行Base::fcnbp3->fcn(); //虚调用:运行时执行D2::fcn//f2是D1中的虚函数//Base中没有定义f2//D2重载了D1的虚函数f2D1 *d1p = &d1obj;D2 *d2p = &d2obj;bp2->f2(); //错误:Base对象中没有名为f2的成员d1p->f2(); //虚调用:执行D1::f2()d2p->f2(); //虚调用:执行D2::f2()//调用非虚函数的例子//fcn(int)是D1中的 非虚函数//Base中没有定义fcn(int)//D2中的fcn(int)隐藏了D1中的fcn(int)Base *p1 = &d2obj; //d2obj是D2类型的对象D1 *p2 = &d2obj;D2 *p3 = &d2obj;p1->fcn(42); //错误:Base中没有接受int的fcnp2->fcn(42); //静态绑定:调用D1::fcn(int)p3->fcn(42); //静态绑定:调用D2::fcn(int)