c++面向对象的三大特性
- 封装;将相同属性的数据和方法封装在一起,加权限区分,用户只能借助公共方法操作私有数据.
- 继承:体现在类和类之间的关系,如果A类继承B类,那么A类直接拥有B类的数据和方法.
- 多态:一个接口(函数),多种功能.
作用域运算符::
::解决归属问题(谁是谁的谁)
结构体类型增强
- c++允许函数作为结构体成员
新增BOOl类型
占1个字节;返回值true或者false;
三目运算符
c++返回的是引用,而c语言返回的是值;
左值和右值
左值:能被赋值的值.(在等号的左边)
右值;只能放右边的值.(不能被赋值的值)
const增强
- 尽量使用const代替#define
- const有类型,可以进行编译器类型的安全检查.#define无类型,不可以进行类型检查
- const有作用域,而#define不重视作用域,宏不能作为命名空间,结构体,类的成员,而const可以.
引用
- 引用的本质:就是给变量名取个别名
- 引用定义的步骤:
1.&别名
2 给哪个变量取别名就定义该变量
3 从上往下整体替换
内联函数
- 在编译阶段,将内联函数中的函数体 替换函数调用处.避免函数调用时的开销.
- 内联函数:必须在定义的时候使用关键字inline修饰,不能在声明的时候使用inline.
- 宏函数和内联函数的区别:
同:宏函数和内联函数 都会在适当的位置进行展开,避免函数调用开销
异: 宏函数的参数没有类型,不能保证参数的完整性.
内联函数的参数有类型,能保证参数的完整性.
宏函数在预处理阶段展开
内联函数在编译阶段展开
宏函数没有作用域的限制,不能作为命名空间,结构体,类的成员
内联函数有作用域的限制,能作为命名空间,结构体,类的成员. - 内联函数的注意事项
在内联函数定义的时候加inline修饰
类中的成员函数默认都是内联函数(不加inline 也是内联函数)有时候就算加上inline也不一定是内联函数(内联函数条件)
条件:->1.不能存在任何形式的循环语句
2.不能存在过多的条件判断语句函数体不能过于庞大
3.不能对函数取地址
有时候不加inline也可能是内联函数
函数重载
- 函数重载是c++的多态的特性(静态多态)
- 函数重载:用同一个函数名,代表不同的函数功能.
- 函数重载的条件:
1.同一作用域,函数的参数类型,个数,顺序不同都可以重载
c++中不能直接将函数名作为函数的入口地址—>函数名和参数共同决定函数的入口地址.
缺省参数
析构函数
- 当对象生命周期结束的时候,系统自动调用析构函数.
- 函数名和类名称相同,在函数名前加~,没有返回值类型,没有函数形参.(不能被重载).
先调用析构函数,再释放对象空间. - 一般情况下,空的析构函数就足够.但是如果一个类有指针成员,这个类必须写析构函数,释放指针成员所指向空间.
拷贝构造函数
- 拷贝构造:本质是构造函数
- 拷贝构造调用时机:旧对象.初始化.新对象,才会调用拷贝构造.
- 如果用户不提供拷贝构造, 编译器会自动提供一个默认的拷贝构造(完成赋值动作—浅拷贝).
拷贝构造和无参构造 有参构造的关系
如果用户定义了拷贝构造或者有参构造 都会屏蔽无参构造.
如果用户定义了无参构造或者有参构造,不会屏蔽拷贝构造
- 拷贝构造几种调用形式
1.旧对象给新对象初始化 调用拷贝构造.
2.给对象取别名 不会调用拷贝构造.
3.普通对象作为函数参数,调用函数时会发生拷贝构造.
4函数返回值普通对象(Visual Studio会发生拷贝构造)(Qtcreater,linux不会发生).
- 拷贝构造的深拷贝和浅拷贝
默认的拷贝构造 都是浅拷贝
如果类中没有指针成员,不用实现拷贝构造和析构函数
如果类中有指针成员,必须实现析构函数释放指针成员指向的堆区空间,必须实现拷贝构造完成深拷贝动作.
对象数组
对象数组:本质是数组,数组的每个元素是对象.
explicit关键字
- explicit防止构造函数隐式转换
//构造函数隐式转换(类中只有一个数据成员)
new和delete堆区空间操作
单例模式
- 单例模式的类只能实例化一个对象.
this指针
- 普通成员函数 默认有一个this指针 指向调用该成员函数的对象.
- this完成链式操作.
友元
- 类将数据和方法封装在一起 加以权限区分 用户只能通过公共方法操作私有数据(封装性)
- 主要用于运算符重载.
- 一个函数或者类 作为了另一个类的友元 那么这个函数或类就可以直接访问另一个类的私有数据.
运算符重载
- 运算符重载是对已有的运算符指定新功能.不能创建新运算.
运算符重载关键字operator
思路:
函数模板
- 将功能相同,类型不同的函数(类)的类型抽象成虚拟的类型.当调用函数(类实例化对象)的时候,编译器自动将虚拟的类型具体化.这个就是函数模板(类模板).
- 关键字template;
函数模板会编译两次:
第一次:是对函数模板本身的编译
第二次:函数调用处将T的类型具体化
函数模板目标:模板为了实现泛型,可以减轻编程的工作量,增强函数的重用性.
- 1.函数模板和普通函数都识别.(优先选择普通函数)
- 2.如果想强制使用函数模板
-
e.g swapall<>(a,b);(加上<>)
- 3.函数模板自动类型推导时,不能对函数的参数进行自动类型转换.
- 4.如果函数模板显示指明T的具体类型,这时函数模板的参数可以自动类型转换.
5.模板的局限性 - 当函数模板推导出T为数组或者其他自定义类型数据,可能导致运算符不识别.
解决方法一:运算符重载
方法二:将函数模板具体化.
纯虚函数
- 只要有一个纯虚函数,这个类称为抽象类.
- 抽象类特点:
-
1.无法实例化对象
-
2.抽象类的子类,必须要重写父类中的纯虚函数,否则也属于抽象类.
虚析构与纯虚析构
多态使用时,如果子类中有属性开辟到堆区,父类指针在析构时候,不会调用子类中析构函数,导致子类如果有堆区属性,出现内存泄漏.
- 虚析构和纯虚析构共性:
可以解决父类指针释放子类对象时不干净的问题.
都需要具体的函数实现. - 区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法: virtual ~类名(){ }
纯虚析构语法: virtual ~类名()=0; 类名::~类名(){};
- 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构.
类模板
- 类模板将类中类型抽象成虚拟类型.
- 1.类模板 实例化对象不能自动类型推导
- 2.类模板 实例化对象必须指明T的类型.
STL的概述
STl的六大组件:容器,算法,迭代器,适配器,仿函数,空间配置
- 容器:存放数据
- 算法:操作数据
- 迭代器:算法通过迭代器操作容器
- 适配器:为算法提供更多的接口.
- 仿函数:为算法提供策略
- 空间配置:为算法,容器提供动态空间.
Vector容器
- vector容器:单端动态数组容器.
deque容器
- 双端动态数组
- Deque容器和vector容器最大差异