侯捷老师C++面向对象高级编程上——笔记(附带自己查询额外知识点)
构造函数
-
成员变量赋值时,尽量采用初始化列表,这样效率更高,因为变量获值分为两步,1 初始化 2 赋值
-
成员函数不修改成员属性的值时(读函数),声明为const常函数(getXX())
-
写函数参数为&(T& param)
-
Const 常对象只能调用常函数
-
不能同时存在,编译器遇到Complex c2()时不知道调用哪个构造函数(把上面的=0默认参数去掉即可)
-
单例设计模式,构造函数放在private里面
-
引用定义:常指针, int* const a = &b; 最好所有的参数都传引用。
-
&操作符:两种含义,一种引用(放在typename后面,得到的是对象的别名,引用),一种是取地址符(放在object前面,得到的是一个指针)
-
引用赋值
-
如果不修改参数值,则加const关键词。
-
相同Class的不同对象互为友元。
-
返回值是否为引用(reference)取决于返回值是否存在(局部生命周期还是已经存在)如果时函数创建的temp变量,则不能返回引用。(尽量返回引用)
操作符重载
-
两种方式:1 成员函数 2 非成员函数
-
所有的成员函数都带有一个隐藏的参数this(指向本对象)
-
连续调用运算符重载,将函数返回值设计成为&
-
全局函数和成员函数区别:是否带有类作用域Complex::
-
当需要创建一个local object时,返回值一定时value 而不是 reference
-
对于特殊操作符<<重载只能选择非成员函数
类设计
-
首先构造函数初始化列表使用
-
其次函数设计时是否设计为const常函数
-
传参是否加引用,是否加const
-
返回值是否为引用
-
重载是否友元函数 友元函数放在private里面
-
A声明B为其友元类,则B所有成员函数可以访问A的私有成员变量
-
A声明FunC为其友元函数,则FunC可以访问A所有私有变量
-
友元函数在C++中不具有传递性
拷贝构造、拷贝赋值、析构函数 -
拷贝构造是构造函数的一种,只有一个参数,是本对象类型的引用。如Complex(Complex& c) ,但是默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。(指针成员共用内存)
-
当含有指针成员时,需要重写析构函数释放内存delete,因为程序默认的析构函数不能释放动态内存。
-
C++类中会有默认的拷贝构造函数和拷贝赋值。(浅拷贝)
-
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
-
只要你的成员还有指针,那么就不可以采用编译器自带的默认拷贝构造函数(会使指针按字节拷贝后,两个指针指向同一个空间地址,导致先前的s1
被删除后,s2的数据也不复存在)
第二行为拷贝构造,第三行为拷贝赋值。
- ‘\0’在strlen函数中不计算入长度。
- C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。
如:
char* m_data = new char[10];
delete[] m_data;
String s = new String(“hello”);
delete s。 - 带有指针成员的类析构函数必须delete指针成员所指向内存空间,否则会导致内存泄漏。
- 声明对象采用堆栈结构 先声明后析构
堆、栈、内存管理
- 堆、栈
栈里面的变量空间系统自行释放,而堆里面的需要手动释放(delete),c1是栈空间,p是堆空间。
-
{}划分作用域,但是加上static之后,变成静态变量,一直存在,直到程序结束才会调用析构函数
-
堆 heap object 生命周期在delete之后(调用析构函数)结束
-
内存泄漏
-
New分配内存三个步骤,第一步申请类型对象大小空间(对象大小一般为类成员变量大小);第二步类型转换(void* -> T*);第三步调用构造函数;
-
Delete两个步骤,第一步调用析构函数删除类成员变量;第二部删除类对象本身指针
-
堆栈区别
-
Delete[] 一定要搭配 new[], new 搭配 delete(调用析构函数的次数不同)
-
Vc编译器内存分配
类模板、函数模板
-
Static声明的成员变量(只有一份)独在一个区(全局,静态区),非静态变量每个对象开辟一个空间存储
-
类成员函数体在内存中只有一份(位于程序代码区)
-
静态函数static没有this指针,因此静态函数只能访问静态成员,静态函数访问推荐以类名加作用域符调用如Complex::get_test()
-
Static成员变量,类内声明,类外初始化
-
宏与模板的区别
-
Namespace 包装封锁代码空间 采用using namespace xxx;
-
Explicit 防止类型隐式转换,用于构造函数声明