大一新生的c++ pp 第十三章基础学习笔记:继承

目录

1.总的领起:

2.派生类的注意点(公有继承):

2.1.为派生类写构造函数(必须):

2.2.派生类与基类的数据类型关系

3.公有继承:

4.虚方法(关键字:virtual)

5.函数联编

6.关键字:protected

7.abc类

8.派生类和new

9.回顾总结

9.1.如果要实现派生,一定要写构造函数。

9.2.如果要复习这一章,重点在于理解这关键两点——公有继承的概念、动态联编和虚函数。

9.3.复习的次要点:new、protect、abc、友元——这四个要素和类继承的碰撞。


1.总的领起:

1.1.类继承的目的:重用代码。

1.2.类继承的功能:添加功能(新的方法)、数据(新的数据成员)。

2.派生类的注意点(公有继承):

2.1.为派生类写构造函数(必须):

1.该构造函数不仅要给自己派生的数据提供构造,还要为原本基类的数据提供构造。

2.派生类无法直接访问基类的私有数据,但可以通过公有方法进行访问。所以派生类的构造函数一般要联动基类的构造函数。

3.程序将先调动基类构造,再调用派生构造。

2.2.派生类与基类的数据类型关系

1.指针(引用)的数据类型方面:基类指针包含派生类指针(派生类的地址可以用基类指针承载,然而反过来则不允许);但基类指针实现派生类时,不能调用派生类的新方法。

2.以1似推,派生类可以用来初始化基类,也可以赋值给基类。原理是构造函数和复制构造函数,它们的参数是引用类型,此时根据1即可。

3.公有继承:

叙述:用集合比喻基类和派生类:基类是大集合,包含一些基础和一些未实现也未知的可能性;派生类是小集合,包含了基类的一些基础和部分实现的可能性——若基类是鱼,派生类可以是鲨鱼、草鱼、金鱼。这时候可以认为鲨鱼是鱼,但不能认为鱼都是鲨鱼。

结论:派生类是基类,基类不是派生类;基类由于没有实现可能性,故不能使用派生类方法。此时指针的数据类型可能因此推论而来:基类指针可以承载派生类地址,但相反则不允许;基类指针实现的派生类不能调用派生类方法。

吐槽:感觉这样的规则更多是为了可以便捷地将派生类的数据通过引用来赋值或者传参给基类。

4.虚方法(关键字:virtual)

4.1.目的:同名方法在基类与派生类中实现不同的功能,类似函数重载。

4.2.注意:在使用指针去调用类的方法时候——如果方法是虚方法,那么将根据指针指向的数据类型进行方法调用;如果不是,则根据指针本身的数据类型进行方法调用。

4.3.注意:基类中的方法声明为虚方法后,派生类的同名方法也将视为虚方法。必要性是:纵然基类有虚方法声明,但在派生类中声明虚方法可以让程序猿知道这个东西是虚方法。所以最后的结论是:两个都声明是虚方法。

4.4.骚操作:虽然基类数据和派生类数据不能直接放到一个数组里,但是可以通过指针数组来实现这个目的。因为基类指针可以承载基类,也可以承载派生。

4.5.注意:虚析构函数的必要性:在4.4骚操作的时候,利用虚方法的特性不仅可以析构派生数据,也可以析构基类数据。

4.6.吐槽:补充上一个吐槽,尬住了,这个规则原来还可以利用来进行骚操作。

5.函数联编

5.1.两种函数联编:静态联编与动态联编。

5.2.静态联编:在编译时候,通过函数名与参数列表即可确定使用的函数;动态联编:对于虚函数而言,还需要确定类对象的类型才能在编译时候确认使用的函数,毕竟虚函数的函数名和参数列表是一样的。

5.3.动态联编原理:在类中添加一个特殊的数据成员,以此来添加辨认。深入解释:这个特殊的数据成员是一个指向函数地址表的指针,该函数地址表即为虚函数表;虚函数表里储存了所有虚函数的地址,通过这个地址,编译器将确定使用哪一个虚函数。

5.4.注意:在基类与派生类进行按值传递时,派生类将损失派生的数据;但如果是指针(引用),将不会损失。

5.5.注意:构造函数不应该成为虚函数。自己的理解是:虚函数的目的是创造相同名字不同行为的函数,构造函数确实有不同的行为,但名字已经不一样了,编译器知道该去使用哪个函数;故强行将其名字统一然后再将其成为虚函数,然后再去使其拥有不一样的行为,感觉是多此一举。

5.6.注意:对于析构函数来说,虚函数还要另外的目的。那就是在使用new与指针的时候,虚的析构函数将很好地将矛头对准基类和派生类。从这个目的上来说,析构函数虚化是有必要的。从5.5的目的上来说,则显得与构造函数差不多。

5.7.注意:友元函数比较特殊,它可以是虚函数,也可以不是,取决于需要。

5.8.注意:如果使用了虚函数,那么应该保持函数名与函数列表一样(即静态联编看不出差异),不然虚函数在5.5上的目的就丧失了;但与此同时,如果返回类型是基类,应修改为派生类;且如果不是虚函数,那么函数名与参数列表也应该不一样,不然静态联编看不出来。

5.9.隐藏现象:派生类会把基类的函数地址列表给复制(继承)下来,如果有同名的虚函数定义在派生类,它的地址将取代所有地址列表中的同名函数,将这些同名虚函数隐藏下来,这或许也是动态联编的原理机制。故若基类存在函数重载现象,那么派生类想将其尽数虚函数化也应该对应地函数重载。

5.10.吐槽:5.8、5.9纯粹个人理解。看的时候有点绕。总之,一张函数地址表安安静静地从基类递给派生类。派生类可以在上面添加不一样的函数,这个不一样是从静态联编角度考虑的;与此同时,派生类也可以添加一样的函数,这个一样也是从静态联编角度考虑的,但是这时候静态联编看不出来了差异了,就得虚函数化,用动态联编看出差异。不过这时,隐藏现象就会发生,但这也正是动态联编的原理。

6.关键字:protected

解释:平行于private、public,特性是派生类和基类的方法都可以访问基类的protect,但对于外界而言,其依旧是private。c++pp建议不要放数据成员于protect,而应该放一些私密的内部函数。

7.abc类

7.1.理念:若派生过程的实现过于复杂,这时可以考虑将两个类的共同点提取出来形成一个新的基类,通过这个基类再去派生这两个类。

7.2.纯虚函数:将虚函数声明的尾部添加=0,虚函数即可成为纯虚函数。拥有纯虚函数的类将无法创建对象,一般用于派生。

8.派生类和new

8.1.回顾:在第十二章中,new和类设计引发了一个问题:多次调用析构,对一块内存多次释放;在那时,因为new引发的问题所以为类重新定义了复制构造、赋值等函数。现在轮到派生类和new。

8.2.如果派生类中新增的数据成员没有使用new,那么其复制构造等函数就不需要再重新定义,默认的已经足够;但如果新增的数据成员使用了new,那么就需要重新定义析构、复制构造、赋值函数。实现的一些细节可以回顾书本。

8.3.友元和派生的骚操作:之前的友元是为了实现重载<<或者>>运算符。在派生类与友元的化学反应中,由于派生类无法访问基类数据,故而有一个骚操作——例如cout<<(基类引用)派生类对象。是的,这就是强制转化的魅力,或者说指针的魅力。

9.回顾总结

9.1.如果要实现派生,一定要写构造函数。

9.2.如果要复习这一章,重点在于理解这关键两点——公有继承的概念、动态联编和虚函数。

9.3.复习的次要点:new、protect、abc、友元——这四个要素和类继承的碰撞。

你可能感兴趣的