为什么要学习C++
- 因为大学没C++
- 面试上要求精通C++
- shader学习也是要求有C++,图形渲染
- 引擎的底层问题,不学C++没办法看懂
- 未来如果需要学习UE4,减少切换时间
怎么学习
- 知乎上关注了C++
- 其次购买了《C++ Primer(第五版)》,2015年11月时候购入的
- 看一些学习的免费课程
C++知识点(不定期更新)
一 对象实例化
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
 | class TV { public:   char name[20];   int type;   void changeVol();   void power(); } int main(void) {   TV tv;   TV tv[20];   return 0; }
 | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 | class TV { public:   char name[20];   int type;   void changeVol();   void power(); } int main(void) {   TV *p = new TV();   TV *q = new TV[20];      delete p;   delete []q;   return 0; }
 | 
二 初始化string对象的方式
| 初始化string对象的方式 |  | 
| string s1; | s1为空串 | 
| string s2(“ABC”); | 用字符串字面值初始化S2 | 
| string s3(s2); | 将s3初始化为s2的一个副本 | 
| string s4(n,’c’); | 将s4初始化为字符’c’的n个副本 | 
| string的常用操作 | 
| s.empty() | 若s为空串,则返回true,否则返回false | 
| s.size() | 返回s的字符个数 | 
| s[n] | 返回s中的位置为n的字符,位置从0开始 | 
| s1+s2 | 将两个串连接成新串,返回新生成的串 | 
| s1=s2 | 将s1的内容替换为s2的副本 | 
| v1==v2 | 判断相等,相等返回true,否则返回false | 
| v1!=v2 | 判断不等。不等返回true,否则返回false | 
三 类内定义与内联函数
- 内联函数 关键字:inline
 类内定义的函数计算机首先作为内联函数去编译,类内定义的函数复杂时才作为普通函数去编译
- 类外定义
 同文件类外定义:函数名写在类内,具体实现写在类外,并且在一个文件中。(游击队)
 分文件类外定义:需要定义一个头文件,头文件名和类名建议一致。在其他文件中使用此类时,需要加上头文件。(正规军)
四 对象结构
- 内存分区- 栈区:int x=0;int *p= null;- 堆区:int *p = new int[20];- 全局区:存储全局变量及静态变量- 常量区:string str = “hello”;- 代码区:存储逻辑代码的二进制
- 对象初始化:一是有且仅有一次,二是根据条件初始化
- 构造函数的规则和特点- 构造函数在对象实例化时被自动调用- 构造函数与类同名- 构造函数没有返回值- 构造函数可以有多个重载形式- 实例化对象时仅用到了一个构造函数- 当用户没有定义构造函数时,编译器自动生成一个构造函数 (非常重要)
- 默认构造函数:没有参数的构造函数
- 初始化列表特性- 初始化列表先于构造函数执行- 初始化列表只能用于构造函数- 初始化列表可以同时初始化多个数据成员
- 拷贝构造函数- 如果没有自定义的拷贝构造函数则系统自动生成一个默认的拷贝构造函数- 当采用直接初始化或复制初始化实例化对象时系统自动调用拷贝构造函数
- 析构函数- 如果没有自定义的析构函数则系统自动生成- 析构函数在对象销毁时自动调用- 析构函数没有返回值,没有参数也不能重载
- 对象的生命历程申请内存->初始化列表->构造函数->参与运算-》析构函数->释放内存
五 const
六 函数
函数参数默认值值
函数重载:在相同作用域内用同一函数名定义的多个函数参数个数和参数类型不同
内容总结
| 内容总结 | —- | 
| 函数参数默认值 | 实参覆盖默认值 | 
| 函数重载 | 名称相同参数可辨 | 
| 内联函数 | inline 效率高 有条件 | 
七内存管理
内存的本质是资源
操作系统掌管内存资源
我们能做申请/归还
申请/归还内存资源就是内存管理
申请内存 (new) 释放内存(delete)
申请内存需要判断是否成功,释放内存需要设空指针
new与delete 配套使用
八对象数组
深拷贝与浅拷贝
当数据成员中含有指针时,浅拷贝会使两个对象的成员指针指向相同的内存地址
深拷贝不是简单的值拷贝,而是将指针成员指向的内存数据也进行拷贝
对象指针
this指针
this指针也是指针类型,所以在32位编译器下也占用4个基本的内存单元,即sizeof(this)的结果为4。
当成员函数的参数或临时变量与数据成员同名时,可以使用this指针区分同名的数据成员。
this指针无需用户定义,是编译器自动产生的。
常成员函数(const)
常成员函数的本质是内部使用常this指针。
常成员函数内使用数据成员时,不能改变数据成员的值。
常成员函数内不能调用普通的成员函数。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 | #include <iostream> using namespace std; class Coordinate { public: 	Coordinate(int x, int y) 	{ 		 		m_iX = x;         m_iY = y; 	}      	void printInfo() const 	{ 	    cout<<"("<<m_iX<<","<<m_iY<<")"<<endl; 	} public: 	int m_iX; 	int m_iY; }; int main(void) { 	const Coordinate coor(3, 5); 	 	const Coordinate *p= &coor;          const Coordinate &c = coor; 	coor.printInfo(); 	p->printInfo(); 	c.printInfo();   	return 0; }
 | 
九继承
公有继承(class A:public B),保护继承(class A:protected B),私有继承(class A:private B)
| 基类成员访问属性 | 继承方式 | 派生类成员访问属性 | 
| private成员 | public | 无法访问 | 
| protected成员 | public | protected | 
| public成员 | public | public | 
| 基类成员访问属性 | 继承方式 | 派生类成员访问属性 | 
| private成员 | protected | 无法访问 | 
| protected成员 | protected | protected | 
| public成员 | protected | protected | 
| 基类成员访问属性 | 继承方式 | 派生类成员访问属性 | 
| private成员 | private | 无法访问 | 
| protected成员 | private | private | 
| public成员 | private | private | 
十继承中的特殊关系
多继承和多重继承
## 人类<-士兵类<-步兵类 ->多重继承
## 一个子类有多个父类,或者一个派生类有多个基类->多继承
虚继承
- 关键字:virtual- A<-B<-D,A<-C<-D,又称菱形继承
十一多态
- 普通虚函数与虚析构函数- Virtual使用限制- 普通函数不能是虚函数
静态成员函数不能是虚函数
内联函数不能为虚函数
构造函数不能是虚函数
在C++中多态的实现是通过虚函数表实现的
每个类只有一份虚函数表,所有该类的对象共用同一张虚函数表
两张虚函数表中的函数指针可能指向同一个函数。
| 1 2 3 4 5 6 7
 | class Shape { public: virtual double calcArea()     {return 0;} virtual double calcPerimeter()=0;  }
 | 
- 纯虚函数和抽象类- 抽象类无法实例化对象
- 纯虚函数:抽象类与接口类- 仅含有纯虚函数的类称为接口类- 成员函数都是纯虚函数。- 接口类更多的表达一种能力或协议
- RTTI 运行时类似识别- typeid<——->dynamic_cast- dynamic_cast注意事项:- 只能应用于指针和引用的转换- 要转换的类型中必须包含虚函数- 转换成功返回子类的地址,失败返回NULL- typeid 注意事项:- type_id 返回一个type_info对象的引用- 如果想通过基类的指针获得派生类的数据类型,基类必须带有虚函数- 只能获取对象的实际类型
继承关系不是RTTI的充分条件,只是必要条件,所以存在继承关系的类不一定可以用RTTI技术
运行时类型别必须建立在虚函数的基础上,否则无需RTTI技术
RTTI技术可以通过父类指针识别其所指向对象的真实数据类型
- 异常处理- 关键字:- try….catch…    throw- 基本思想:主逻辑与异常处理分离- try与cath是一对多的关系- 常见的异常- 数组下标越界- 除数为0- 内存不足
- ##隐藏与覆盖,什么叫覆盖,覆盖与隐藏之间的关系 
- 早绑定和晚绑定- 概念:指相同对象收到不同消息或者不同对象收到相同消息产生不同的动作- 静态多态(早绑定),编译之前到底使用什么函数,函数被编译进去了- 动态多态(玩绑定)- 十一友元函数和友元类
- 友元函数和友元类- 关键字:friend- 友元全局函数- 友元成员函数
- 关于友元的注意事项- 友元关系不可传递- 友元关系的单向性- 友元声明的形式及数量不受限制友元只是封装的补充
- 静态函数- 定义静态成员函数和静态数据成员都需要static关键字。- 公有静态成员函数可以被类直接调用。- 静态数据成员不能在构造函数初始化,必须单独初始化。- 注意事项- 静态数据成员必须单独初始化- 静态成员函数不能调用非静态成员函数和非静态数据成员- 静态数据成员只有一份,且不依赖对象而存在*## 运算符重载- 本质是函数重载- 一元运算符重载- -(负号)的重载:友元函数重载,成员函数的重载- ++符号的重载:前置++符号重载[Coordinate& operator++()],后置++符号重载[Coordinate operator++(int)]- 二元运算符- +号:成员函数重载,友元函数重载- << 不可用成员函数重载,只可用友元函数- 模版函数,模版类- 关键字:template typename class
| 1 2 3 4 5 6 7 8 9 10 11
 | template <typename T> void display(T a) { 	cout << a << endl; } template < typename T, class S> void display(T t, S s) { 	cout << t << endl; 	cout << s << endl; }
 | 
特别提醒:模版代码不能分离编译
模版类
STL:C++标注模版库
STL:Standard Template Lib
vector 向量的本质:对数组的封装
| 初始化Vector对象的方式 |  | 
| vector v1; | vector保存类型为T的对象。默认构造函数v1为空 | 
| vector v2(v1); | v2是v1的一个副本 | 
| vector v3(n,i); | v3包含n个值为i的元素 | 
| vector v4(n); | v4包含有初始化元素的n个副本 | 
链表
迭代器相当于指针
值,指针,内存地址,使用区别