C++基础(三)
一、C++的三大特性
封装、继承、多态
多态简而言之就是用父类型的指针指向子类型的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针具有“多种形态”。
多态意味着多种形态,当类之间存在层次结构,且不同类之间通过继承关联时,就会用到多态。
需要在基类中将公有函数名设置为虚函数,此时编译器就会通过指针内容调用函数,而非通过指针类型调用函数(静态多态)。
1、多态
普通函数的继承是实现继承,派生类继承了基类函数,继承的是函数的实现,虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态。所以,如果不是为了实现多态,不要把函数定义成虚函数
2、虚表与vptr指针
当类中声明虚函数的时候,编译器会在类中生成一个函数虚表。虚函数表是一个存储类成员函数指针的数据结构,这个虚函数表由编译器自动生成和维护,virtual成员函数会被编译器放入虚函数表中,存在虚函数时,每个对象中都有一个指向虚函数表的指针。
二、const的作用
1、定义const常量,可以防止意外的修改
2、相较于#define便于进行类型安全检查
3、相较于#define更节约内存空间
4、编译器不为普通const菜场里那个分配存储空间,使得没有存储和读内存的操作,提高了效率。
三、析构函数
是类的一种特殊的成员函数,会在每次删除所创建的对象时执行,它不会返回任何值,也不会有任何参数。
析构函数有助于在跳出程序前释放资源。
基类的析构函数最好写成虚基类,此时派生类的析构函数会自动重写基类的析构函数,可以理解为编译器对析构函数做了特殊处理。
四、内联函数(inline)
目的是提高函数的执行效率,但是必需要和函数定义体放在一起,仅与函数声明体放在一起没有任何意义。
缺点:滥用内联函数会让程序变慢。
五、钻石继承问题(菱形继承)

问题描述:D类中会有两份A类的成员(包括数据和方法),所以D的对象会包含A的两个子对象,这会导致调用函数不明确(D的对象不清楚应该调用B中的函数还是C中的函数)。
解决方法:class B : virtual public A{};
class C : virtual public A{};
即为B、C虚继承A类后,类D中将会只有一个A的子对象。
六、同名覆盖问题
场景描述:父类指针指向子类时,调用了一个在父类和子类中均存在的函数(在子类中把父类的此函数进行了重写),此时调用的是哪个函数。
1、父子间的赋值兼容
(1)子对象可以直接赋值/初始化父类对象。
(2)父类指针可以直接指向子类对象。
(3)父类引用可以直接引用子类对象。
2、父类指针(引用):当使用父类指针直接指向(引用)子对象时
(1)子类退化为父类对象。
(2)只能访问父类中定义的成员
(3)可以直接访问被子类覆盖的同名成员。
3、特殊的同名函数
子类中可以重定义父类中已经存在的同名函数,这种重定义发生在继承中,称为函数重写。
若采用父类指针指向子类对象,并调用在子类中重写过的函数,此时会调用父类对象中的函数为了解决此问题,引入多态的概念(通过虚继承避免)。
七、引用
引用就是某一变量(目标)的一个别名,对引用的操作和对变量直接操作完全一样。
引用的声明方法: 类型标识符 &引用名=目标变量名。
int a;
int &ra =a; 此时定义了一个引用ra,它是变量a的引用,也即别名。
引用只是一个别名,本身不是数据类型,也不占用存储单元,系统也不分配存储单元,对引用取地址等价于对目标变量取地址。
无法建立对数组的引用。
1、常引用
const 类型标识符 &引用名= 目标变量名
避免通过引用更改目标变量的值,达到了引用的安全性。
2、引用作为返回值
(1)、 以引用返回函数值的时候,定义函数时需要在函数名前加&。
(2)、用引用返回一个函数值的好处是,在内存中不产生被返回值的副本,可以节约内存开销。

浙公网安备 33010602011771号