c++类【高潮】

类继承

和直接复制源代码修改相比,继承的好处是减少测试。

基类:原始类,

派生类:继承类,基于基类丰富更多内容的类。

继承一般用公有继承,class 派生类名 : public 基类名{......};

公有继承,基类的公有部分变成派生类的公有部分,基类的私有部分,还是基类的私有部分,派生类只能通过基类的公有方法和保护方法访问。这也说明,数据的安全性。一旦定义为私有,终生私有,派生出来也不会有权读取。

派生类构造函数

派生类,必须创建自己的构造函数。但是,派生类不能直接访问基类的私有数据。所以,派生类又必须使用基类的构造函数来初始化。

可曾还记得:成员初始化列表?是不是在哪见过?

只能通过这种方式给基类初始化,因为,创建派生类,要先创建基类,因为派生类包括基类数据。所以,在派生类的构造函数初始化时,要先有基类对象,所以,通过成员初始化列表法,在派生类生成前,先生成基类给派生类对象使用。

派生类析构函数

先执行派生类的构造函数,再调用基类的析构函数。

使用派生类

派生类和基类的特殊关系:派生类可以使用基类的方法(当然,只能使用基类公有的方法)。

基类指针可以指向派生类的对象,但是,反过来不行。可以这么理解,派生类是基于基类来的,派生类的东西要多一些,基类的东西少一些,这样,基类有的,派生类一定有,而派生类有的东西基类不一定用,因此,用基类指针指向派生类对象,用这个指针调用方法时,一定是能存在的。而如果用派生类指针指向基类,派生类更强大,指向的东西派生类可能没有,因此就可能出错。因此,不允许用指向派生类的指针指向基类对象,但可以用指向基类的指针指向派生类对象。

这段比较别扭,从包含可被包含的角度理解,会容易些。就像你可以是你我去父亲的儿子,但不能反过来。

多态公有继承

多态(重载)公有继承,多态就是重载,重载更好理解一些,多态有点过于抽象,不好理解。

类里为啥还有重载?主要是因为,基类的方法A,如果派生类觉得这个函数不好用,但是又不能给个新名字,因为新名字可能就没这么方便理解了,所以,派生类就定义一个和基类方法名称一样的函数,但是呢,做的内容可能就不一样了,或者做的更好了。这个时间,就在派生类的重新定义了方法A。

当然 还有另一个方法,虚函数......

好了,这里回忆一下,我们学了几个概念了:内联函数,友函数、虚函数。这些函数为什么存在呢?

内联函数:方便提升高频调用某个方法的效率,就搞了个内联函数,inline 开头。

友函数:为了不是成员函数,还可以访问类的私有数据,就搞了个友函数,friend开头。

虚函数:为了方便派生类重载方法,搞了个虚函数。

虚函数的这个方便之处在于,还记得开头说的:可以将派生类对象赋值给指向基类的指针,但反过来不行。这个规则会带来一个问题,当基类指针赋值的是派生类对象时,那么当这个指针调用一个基类和派生类都有的函数(方法)时,这个指针到底是调用基类的方法,还是派生类的方法?理论上,基类的指针指向派生的对象,指针也只是调用这个派生对象里基类的方法(因为派生对象继承基类的方法)。因此,虚函数的意义就在于,在基类指针指向派生类对象时,这个指针按指向的对象调用方法。也就是说,基类指针指向派生类对象,就调用派生对象的方法,指向基类对象,就调用基类对象的方法。

所以, 一般,基类的析构函数也定义为虚函数,能够保证派生类对象退出时,会执行完派生类析构函数后,继续执行基类的析构函数。否则基类指向派生类对象时,基类析构函数不是虚函数时,就只会调用基类的析构函数,而不会调用派生类的析构函数。

所以,之所在这么复杂,都是因为"指向基类的指针可以指向派生类对象"造成的。

静态联编和动态联编

因为"指向基类的指针可以指向派生类对象"(万恶之源),导致调用函数的时候,在编译阶段不能确认是用哪个函数,因此,只有在运行的时候才能确定,到底调用的是哪人函数,这种让编译器在运行时才选择调用函数叫动态联编。

静态联编是指在编译阶段就已知调用函数,使用静态联编。

对非虚函数使用静态联编,对于虚函数使用动态联编。

至于动态联编的实现方法,可不不必知道。

总结

如果,在派生类中要重新定义,在基类中,该方法要定义为虚函数。

构造函数不能定义为虚函数,因为不可继承。

析构函数一般要定义为虚函数。

友元函数不能是虚函数,因为友元函数不是类的成员函数。

如果重新定义了继承的方法,要确保与原型完全相同(指特征标),返回类型需要根据新的类进行修改,保持与新类一致。

如果基类的方法有重载,在派生类中,要重新定义所有的基类重载版本,否则,派生类只能调用重新定义的几个版本,其它基类的版本将被隐藏,派生类不能用没有重新定义的版本。

访问控制(protected)

忘记protected这个成员吧,就当只有public和private这两种。protected没啥好处。

抽象基类

纯虚函数?好变态,虚函数还不够,还整出来一个纯虚函数。

纯虚函数:声明虚函数原型时,直接赋值=0;就是说这个虚函数是纯虚函数。

声明 纯虚函数,不需要为类实现他,等到谁继承他时,继承他的派生类再实现他。

包含纯虚函数的基类,就是一个抽象基类。这种类,不能直接创建对象,他只能被继承。

继承和动态内存分配

派生类与new

动态内存分配就是使用new方法了。

继承类,主要考虑就是基类里使用了new方法来对成员分配空间,这个时候,继承时,如何释放基类里new开辟的内存空间,复制和,和赋值时,怎么进行深度复制,而不是执行浅复制(只复制地址,而不复制地址指向的值,导致指向多个对象指向同一个内存这种混乱)。

因此,对于基类有使用new为成员开辟内存的情况,需要考虑用个函数:

析构函数,复制构造函数,重载赋值运算符。

分两种情况:

1、派生类没有使用new为自己的成员分配内存,不需要重新定义上面3个函数。

2、派生类使用new了。必须重新定义上述3个函数。

派生类如何使用基类友元函数

第1步、通过基类的友元函数访问

第2步、通过强制类型转换,将派生类对象转换为基类对象。传递为基类对象的友元函数。

总结

1、编译器会自动创建一些公有成员函数

自动创建的函数,表明很重要

默认构造函数。(自动创建的,就啥也不做),一般建议提供默认构造函数,不要让编译器自动创建。

复制构造函数。一般有4种情况使用复制构造函数:将一个对象初始化为同类的另一个对象;按值递给函数;按值返回对象;编译器生成临时对象。如果类声明里,有使用new分配内存时,要重新定义复制构造函数。

赋值运算符。同上关注是否有new,要不要重定义。

2、其它

转换函数:将类对象转换为其它类型时要定义转换函数,一般是转换为其它基础类型,如int,float,double等。

explicit:用于转换函数和构造函数,表示不允许隐式,必须显示调用。

按值和按引用传递对象,一般建议按引用传递。一个是因为效率,一个是因为虚函数。

按值返回和按引用返回对象,一般按引用返回。

const:在一个函数头,有3个地方可以使用const。开始,中间,和结尾,不同位置,限制的目标不同。开始是限制修改返回值,中间是限制不修改传递的参数,结尾是限制这个函数不能修改对象自己的成员。

类的派生是is-a的关系。

构造函数,析构函数,赋值函数不能被继承。

相关推荐
筏.k8 分钟前
C++ asio网络编程(4)异步读写操作及注意事项
服务器·网络·c++
炬火初现11 分钟前
Qt 的原理及使用(1)——qt的背景及安装
开发语言·qt
weixin_11012 分钟前
Qt 无边框窗口,支持贴边分屏
c++·qt
gaoenyang76052512 分钟前
QT Creator配置Kit
开发语言·qt
浪裡遊26 分钟前
Typescript中的对象类型
开发语言·前端·javascript·vue.js·typescript·ecmascript
杨-羊羊羊34 分钟前
什么是深拷贝什么是浅拷贝,两者区别
开发语言·前端·javascript
Cuit小唐44 分钟前
C++ 组合模式详解
开发语言·c++·组合模式
正在走向自律1 小时前
Python 自动化脚本开发秘籍:从入门到实战进阶(6/10)
开发语言·python
hallo-ooo1 小时前
【C/C++】const关键词及拓展
c语言·c++
代码AC不AC1 小时前
【C++】模板初阶
开发语言·c++·学习分享·技术交流·模板初阶