C++基础知识概念(三)

C++基础知识概念(三)

51 怎样区别虚函数和纯虚函数?两者都有什么作用
虚函数,在类成员方法的声明(不是定义)语句前加“virtual”, 如 virtual void func()
纯虚函数,在虚函数后加“=0”,如 virtual void func()=0
对于虚函数,子类可以(也可以不)重新定义基类的虚函数,该行为称之为复写Override。
对于纯虚函数,子类必须提供纯虚函数的个性化实现。
在派生子类中对虚函数和纯虚函数的个性化实现,都体现了“多态”特性。

但区别是:子类如果不提供虚函数的实现,将会自动调用基类的缺省虚函数实现,作为备选方案;子类如果不提供纯虚函数的实现,编译将会失败。尽管在基类中可以给出纯虚函数的实现,但无法通过指向子类对象的基类类型指针来调用该纯虚函数,也即不能作为子类相应纯虚函数的备选方案。(纯虚函数在基类中的实现跟多态性无关,它只是提供了一种语法上的便利,在变化多端的应用场景中留有后路。)

虚函数:当使用类的指针调用成员函数时,普通函数由指针类型决定,而虚函数由指针指向的实际类型决定。所以虚函数的调用时由指针所指向内存块的具体类型决定的。

纯虚函数:纯虚函数是在基类中声明的虚函数,它要求任何派生类都要定义自己的实现方法,以实现多态性。实现了纯虚函数的子类,该纯虚函数在子类中就变成了虚函数。

定义纯虚函数是为了实现一个接口,用来规范派生类的行为,也即规范继承这个类的程序员必须实现这个函数。派生类仅仅只是继承函数的接口。纯虚函数的意义在于,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但基类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。

含有纯虚函数的类称之为抽象类,它不能生成对象(创建实例),只能创建它的派生类的实例。抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。

抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。

52 存储类说明符有哪些?它们的作用是什么
auto存储类:auto关键字有两种情况:声明变量时根据初始化表达式自动推断该变量的类型,声明函数时函数返回值的占位符。
• register存储类:定义存储在寄存器而不是RAM中的局部变量,这样的情况下,变量的最大尺寸取决于寄存器的大小,且不能对其使用取地址运算符(&)。
static存储类:指示编译器在程序的生命周期内保持局部变量的存在,不需要在每次进入和离开其作用域时分配内存和释放内存,可以用于保持局部变量的值。同时,也能够用于修饰全局变量,修饰全局变量时,使变量作用域限制在声明它的文件内。
extern存储类:用于提供一个全局变量的引用,全局变量对于所有的程序文件都是可见的。使用extern关键字时,不会初始化变量,只会把变量名指向一个之前定义过的存储位置。
mutable存储类:适用于类的对象,mutable数据成员通过const成员函数修改。

53 虚函数、纯虚函数
1、类里如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被覆盖,这样的话编译器就可以使用后期绑定来达到多态。而纯虚函数只是一个借口,是个函数的声明而已,它要留到子类里去实现。
2、纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容,要求各派生类根据实际定义自己的版本,纯虚函数的声明格式为:virtual 函数类型 函数名(参数表) = 0;
3、虚函数在子类里面可以不重写;但纯虚函数必须在子类实现才可以实例化子类。
4、带纯虚函数的类叫抽象类,这种类不能直接生成对象,而只能被继承,并重写其虚函数后才能被使用。抽象类被继承后,子类可以继续是抽象类,也可以是普通类。

54 引用和指针有何区别?
★ 相同点:

  1. 都是地址的概念;
    指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
    ★ 区别:
  2. 指针是一个实体,而引用仅是个别名;
  3. 引用使用时无需解引用(*),指针需要解引用;
  4. 引用只能在定义时被初始化一次,之后不可变;指针可变;
  5. 引用没有 const,指针有 const
  6. 引用不能为空,指针可以为空
  7. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
  8. 指针和引用的自增(++)运算意义不一样;
    8.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。

55 派生类构造函数执行的次序
1、调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右)
2、对派生类新增的成员对象初始化,调用顺序按照它们在类中声明的顺序
3、执行派生类的构造函数体内的内容

56 类型兼容规则
类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。注意这里是使用以公有继承方式继承的派生类,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。
1、派生类对象可以隐含转换为基类对象,即用派生类对象中从基类继承来的成员,逐个赋值给基类对象的成员。
2、派生类的对象也可以初始化基类对象的引用。
3、派生类对象的地址也可以隐含转换为指向基类的指针。

57 虚基类
• 当出现 A->B,A->C,B、C->D,这种情况,即D的直接基类B、C都是从A继承过来的,那么这些同名数据成员就会在内存中存在多个副本,同一个函数名会有多个映射。
• 这时可以使用作用域分辨符来唯一标识并分别访问他们,也可以将共同基类(A)设置为虚基类,这时从不同路径继承过来的同名数据成员在内存中就只有一个副本,同一个函数名也只有一个映射。
[注意]:如果虚基类声明有带形参的构造函数,且没有声明默认形式的构造函数,那么直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化

58 构造一个类的对象的一般顺序
1、若有直接或间接虚基类,先执行虚基类的构造函数。
2、若有其他基类,则按照它们在继承声明列表中出现的次序,分别执行它们的构造函数(但是不再执行它们虚基类的构造函数)。
3、按照在类定义中出现的顺序,对派生类中新增的成员对象进行初始化。
4、执行构造函数的函数体。

59 虚析构函数
如果一个类的析构函数是虚函数,那么由它派生而来的所有子类的析构函数也是虚析构函数。
虚析构函数在删除指向子类对象的基类指针时,可以调用子类的析构函数来实现释放子类堆内存。

60 虚表
• 每个多态类各有一个虚表(virtual table),虚表的内容是由编译器安排的。
• 虚表中有当前类的各个虚函数的入口地址。
• 对于每个含有虚函数的类,它的对象都隐含了一个指向虚表的指针(vptr)。
• 派生类的虚表中,基类声明的虚函数对应的指针放在前面,派生类新增的虚函数的对应指针放在后面,这样一个虚函数的指针在基类虚表和派生类虚表中具有相同位置。
• 执行一个类的构造函数时,首先被执行的是基类的构造函数,因此构造一个派生类的对象时,该对象的虚表指针首先会被指向基类的虚表。只有当基类构造函数执行完后,虚表指针才会被指向派生类的虚表,这就是基类构造函数调用虚函数时不会调用派生类的虚函数的原因。

61 动态绑定的实现
1、构造函数中为对象的虚指针赋值。
2、通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口。
3、通过该入口地址调用虚函数

62 数组指针
• float (*pointer)[4]
pointer是一个指向有4个float类型的数组的指针和pointer[][4]相同(可以理解为指向4个一维数组头部)
• float *pointer[4]
pointer是一个数组,数组中有4个指向float类型的指针

63 组合类对象的初始化次序
1、首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)初始化,顺序是成员在类体中定义的次序。
①成员对象构造函数调用顺序:按对象成员的定义顺序,先声明先构造。
②初始化列表中未出现的成员对象,调用默认构造函数(即无形参的)初始化。
2、处理完初始化列表后,再执行构造函数的函数体

64 静态、动态生存期
静态生存期
1、这种生存期与程序的运行期相同。
2、在文件作用域中声明的对象具有这种生存期。
3、在函数内部声明静态生存期对象,要冠以关键字static。
动态生存期
1、开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。
2、块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生存期对象)。

65 常成员
常成员函数:
1、使用const关键字说明的函数。
2、常成员函数不更新对象的数据成员。
3、常成员函数说明格式:类型说明符 函数名(参数表) const。
4、const关键字可以被用于参与对重载函数的区分。
5、通过常对象只能调用它的常成员函数

常数据成员:
1、使用const说明的数据成员。
2、只能用常函数去处理常对象。
3、通过构造函数的初始化列表给对象的常数据成员赋初值。
4、const对象必须被初始化。

66 C++程序的一般组织结构
一个工程可以划分为多个源文件,例如:
①类声明文件(.h文件)
②类实现文件(.cpp文件)
③类的使用文件(main()所在的.cpp文件)

67 编译预处理
1、#include 包含指令
①将一个源文件嵌入到当前源文件中该点处。
②#include<文件名>:按标准方式搜索,文件位于C++系统目录的include子目录下。
③#include “文件名”:首先在当前目录中搜索,若没有,再按标准方式搜索
2、#define 宏定义指令
①定义符号变量,很多情况下已被const定义语句取代。
②定义带参数宏,已被内联函数取代。
3、#undef
①删除由#define定义的宏,使其不再起作用。

68 函数指针
1、定义形式:存储类型 数据类型 (*函数指针名)()
2、含义:函数指针指向的是程序代码存储区
3、函数指针的典型用途——实现函数回调
①通过函数指针调用的函数
• 例如将函数的指针作为参数传递给一个函数,使得在处理相似事件的时候可以灵活的使用不同的方法。
②调用者不关心谁是调用者
• 需知道存在一个具有特定原型和限制条件的被调用函数。

69 this指针
this指针存在的目的是保证每个对象拥有自己的数据成员,但共享处理这些数据成员的代码。
1、隐含于类的每一个非静态成员函数中(静态成员函数是没有this指针的,若使用会编译错误)。
2、this总是指向当前对象,因此this是一个常量指针。
3、指出成员函数所操作的对象。
• 当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针。
4、this指针使串联的函数调用成为可能,即在同一条语句里多个函数被调用(此时函数的返回类型是引用,return *this)。

70 动态申请内存操作符 new:new 类型名T (初始化参数列表)
• 功能:在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值。
• 结果值:成功:T类型的指针,指向新分配的内存; 失败:抛出异常。
释放内存操作符delete:delete 指针p
• 功能:释放指针p所指向的内存。p必须是new操作的返回值。

71 动态创建多维数组
new 类型名T[第一维长度][第二维长度]
• 如果内存申请成功,new运算返回一个指向新分配内存首地址的指针。
• 例如:char (*fp)[3]; fp = new char[2][3]; (fp指向fp[0][0],fp+1指向fp[1][0])

72 智能指针
1、unique_ptr:不允许多个指针共享资源,可以用标准库中的move函数转移指针;
2、shared_ptr:多个指针共享资源;
3、weak_ptr:可复制shared_ptr,但其构造或者释放对资源不产生影响。

73 继承与派生概述
1、继承与派生是同一过程从不同角度看
• 保持已有类的特性而构造新类的过程称为继承
• 在已有类的基础上新增自己的特性而产生新类的过程称为派生
2、被继承的已有类称为基类(或父类)。
3、派生出的新类称为派生类(或子类)。
4、直接参与派生出某类的基类称为直接基类。
5、基类的基类甚至更高层的基类称为间接基类。

74 构造函数执行顺序
1、调用基类构造函数
• 顺序按照它们被继承时声明的顺序(从左向右)。
2、对初始化列表中的成员进行初始化。
• 顺序按照它们在类中定义的顺序
• 对象成员初始化时自动调用其所属类的构造函数(由初始化列表提供参数)
3、执行派生类的构造函数体内容。

75 虚基类及其派生类构造函数
1、建立对象时所指定的类称为最远派生类
2、虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。
3、在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中为虚基类的构造函数列出参数。如果未列出,则表示调用该虚基类的默认构造函数。
4、在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,其他类对虚基类构造函数的调用被忽略。

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值