C++读书笔记
1.定义于函数体内的内置类型的对象如果没有初始化,则其值未定义。类的对象如果没有显示地初始化,则值由类自己确定
2.c++是一种静态类型语言,其含义是在编译阶段检查类型。检查类型的过程叫类型检查。对象的类型决定了对象能参与的运算。所以编译器必须知道每一个实体对象的类型,并要求我们在使用某个变量之前必须声明类型。
3.引用
引用是一个变量的别名,即是一段内存空间的代号。
如果要使一个已经存在的非只读变量拥有只读属性,只需要定义一个新的const变量做为它的引用,则该新的变量为只读的。
当使用字面常量对const引用进行初始化时,c++编译器会为常量值分配空间,并将引用名作为这段内存空间的别名,即该const引用会用该段内存,取值的时候不会去符号表拿而是去该段内存拿。
当用一个引用对另一个引用初始化时,新的引用跟另一个引用所代表的是同一段内存空间的别名,取地址时结果相同。
引用的本质:在c++中内部实现是指针常量。
int &b = a; ----> int* const b = &a;
// 指针指向不能改,也说明引用不能更改
b=20; —> *b = 20; // 解引用
4.函数重载—>在同一个作用域中
函数重载条件:参数个数不同、参数类型不同
两个或多个不同的函数用同样的名字完成不一样的操作,参数的个数、类型不一样,让编译器去选择对应函数操作(函数的返回值不可以作为函数重载的条件)
编译器无法直接通过函数名得到重载函数的入口地址。
5.class 和struct的区别:
class和struct 都是定义数据类型,区别在于默认的访问权限不同,class的默认访问权限是private,struct是public,并且class类的实例化对象可以继承,而struct不能。
6.explicit
C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit,意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式)。
explicit关键字的作用就是防止类构造函数的隐式自动转换,只对一个参数的构造函数有效,两个或者两个以上的无效,除非参数里面有默认参数。
7.内存分区
代码区:存放函数体的二进制代码,由操作系统进行管理
全局/静态存储区: 存放全局变量和静态变量以及常量,程序结束后由操作系统释放
栈区:由编译器自动分配释放,存放函数的参数、以及局部变量–>不能返回局部变量的地址,栈区数据在函数执行完后自动释放
堆区:由程序员手动分配和释放,若不释放,程序结束后系统回收–>malloc() new() ,内存空间不连续,因此会产生内存碎片。对应的free()/delete
在堆区创建有一个整形的int数组:int *arr = new int[10];
释放数组加[] delete []arr;
8.C++四种强制类型转换
去const属性用const_cast
基本类型转换用static_cast
多态类之间的类型转换用dynamic_cast
不同类型的指针类型转换用reinterpret_cast
static_cast:
类似C风格的强制转换,进行无条件转换,静态类型转换:
1)基类和子类之间的转换:其中子类指针转换为父类指针是安全的,但父类指针转换为子类指针是不安全的(基类和子类之间的动态类型转换建议用dynamic_cast)。
2)基本数据类型转换,enum,struct,int,char,float等。static_cast不能进行无关类型(如非基类和子类)指针之间的转换。
3)把任何类型的表达式转换成void类型。
4)static_cast不能去掉类型的const、volatile属性(用const_cast)。
9.析构和构造函数
析构函数:
类的析构函数也是类的一种特殊的成员函数,在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值也不能带有任何参数,不能发生重载
析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源
无参构造函数:
当类中未定义构造函数时,编译器默认提供一个无参构造函数,并且函数体为空
拷贝构造函数:
拷贝构造函数在创建对象时,是使用之前同一个类创建的对象来初始化新创建的对象
如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
不能利用匿名拷贝构造函数给匿名对象赋值。
拷贝构造函数通常用于:
通过使用另一个同类型的对象来初始化新创建的对象。
复制对象把它作为参数传递给函数参数。(值传递)
复制对象,并从函数返回这个对象。
10.深拷贝和浅拷贝
浅拷贝:简单的赋值拷贝操作
问题:堆区的内存可能会被重复释放 —>自己实现一个拷贝构造函数
深拷贝:在堆区重新申请空间,进行拷贝操作
11.对象的构造顺序
局部对象的构造顺序依赖于程序的执行流,即main函数自上而下的顺序
堆对象的构造顺序依赖于new的使用顺序
全局对象的构造顺序是不确定的。所以,在程序当中尽量不使用全局变量,且全局变量之间不要有依赖性。
12.单个对象的构造顺序
调用父类的构造过程
调用成员变量的构造函数(调用顺序与声明顺序相同)
调用类自身的构造函数
类中的const问题
const对象本质只是只读变量,而不是常量,可用const_cast改变const属性
const对象只能调用类中的const成员函数
const成员函数中不能修改成员变量的值
13.类中静态成员变量
静态成员变量属于整个类所有。
静态成员变量的生命周期不依赖于任何对象,程序结束其生命周期才结束。
可以直接通过类名::直接访问公有的静态成员变量。
所有对象共享类的静态成员变量。
可以通过对象名访问公有静态成员变量。
静态成员变量的内存不属于具体的某一个对象,当sizeof(一个具体对象)时,不包括静态成员变量的大小 静态成员变量特性。