C++ c语言的const和c++的const/结构对象内存的区别、拷贝构造、赋值函数、静态成员、单例模式、mutable、 explicit关键字
C语言中的const与C++中的区别?
在C语言和C++语言中const都是用来保护数据的,且C++中还对const保护的数据进行了优化,一旦数据被const保护,就不会再去内存中读取数据,而是一直使用最初的,这样哪些数据被强行修改也不会造成影响。 C++中的const还可以用来修饰成员函数,这种被const修饰的成员函数被称为常函数,这种常函数隐藏的this指针会被cons保护。
没有成员的的结构对象,在C语言和C++中分别占多少个字节内存,为什么?
C语言中的空结构对象0字节,而C++中的1字节。C++的空结构对象之所以有1字节是因为 C++中的类、结构、联合可以有成员函数。
拷贝构造函数
拷贝构造是一种特殊的构造函数,格式:
类名(const 类名& that)
{
}
调用拷贝构造函数的情况
用旧对象给新对象初始化时会自动调用拷贝构造。
例:
Test t;
Test t1 = t; // 自动调用拷贝构造
拷贝构造的任务
顾名思义就是拷贝构造负责把旧对象中的成员变量的值拷贝给新对象,默认情况下编译器会自动生成一个拷贝构造完成上任务。
需要手动实现拷贝构造函数的情况
当对象中有指针变量,默认的拷贝构造只拷贝指针变量的值(浅拷贝),这样两对象的指针变量则会指向同一个目标,如果该指针指向的是堆内存,当执行析构函数时,该内存会被delete两次,从而出现内存崩溃。
这种情况需要程序员手动实现拷贝构造,在拷贝构造中给新对象的指针成员重新分配堆内存,并把旧对象的指针成员所指向的数据,拷贝到新对象的指针成员所指向的内存(深拷贝)。
什么深拷贝与浅拷贝?
将旧对象完完整整的复制给新对象,让新对象实例化,这叫做浅拷贝。对象的成员变量里面有指针时,将旧对象拷贝给新对象的时候,拷贝的是指针指向的值而不是指针本身,这叫深拷贝。
赋值函数
所谓的赋值函数就是一个对象给另一个对象赋值时自动调用的函数,原因是在C++中是把运算符当作函数处理的,当使用运行符时就会调用相应的运算符函数,所以赋值运算符调用的就是赋值函数。
类名& operator=(const 类名& that)
{
}
调用赋值函数的场景
旧对象给旧对象赋值时会自动调用赋值函数。
Test t1,t2;
t1 = t2;
赋值函数的任务
负责把对象成员的值赋值给另一个对象的成员,与拷贝构造负责的任务相同,但业务逻辑不同,默认情况下编译器也自动生成的赋值函数。
什么时候需要手动实现赋值函数
当需要赋值函数深拷贝时,要手动实现赋值函数。
mutable关键字
如果成员变量需要在常函数中被修改,那就只需要用 mutable 修饰即可。
explicit关键字
如果一个类的构造函数是单参构造,那么该构造函数的参数类型就具备向该类隐式转换的功能。
如果不想使用此功能,可以在单参构造函数前加 explicit 关键字,该单参构造函数不会再提供隐式类型转换的功能。
静态成员
普通成员
成员变量:每个类对象中者有一份成员变量,不同的类对象之间有成员变量没有关系。
成员函数:隐藏了一个this指针参数。
什么是静态成员
被 static 修饰的成员变量或成员函数。
静态成员特点
静态成员变量
1、存储一份在data或bss内存段,所有类对象共享使用静态成员。
2、在类的内部声明,在类外定义、初始化,在定义不需要再加static关键字。
class Test
{
static int num; // 声明
};
int Test::num = 1234; // 定义和初始化
3、在成员函数可以直接访问。
4、如果具有public属性,也可以在类外直接访问,使用起来相当于全局变量。
静态成员函数
没有隐藏的this指针参数,所以静态成员函数中无法直接访问其它普通成员变量和成员函数,但可以直接访问静态成员变量和静态成员函数。
调用方法:
对象.静态成员函数();
类名::静态成员函数();
静态成员的作用
1、静态成员相当于多了一种类作用域的全局变量、全局函数。
2、静态成员变量适合存储所有类对象的共享属性,这样可以节约内存。
3、静态成员函数作为访问静态成员变量的接口,它还可以在不破坏封装怀的前提下让一个类具备管理自己的能力。
单例模式
定义: 单例模式,只能创建一个对象的类。
单例模式使用场景举例
日志管理器
进程管理器
网站的访问计数器
线程池、内存池、数据池
连接管理器
单例模式的实现原理
1、禁止在类的外部创建类对象
把构造函数设计为 private
2、确保类对象只有一份
在类定义一个静态指针或类对象。
3、提供一个接口用于获取唯一的类对象
单例模式的分支
单例模式又细分为懒汉模式和饿汉模式。
饿汉模式
当程序运行时就已经把单例对象创建完成,不管后面是否会用到。
优点:线程安全,不会被多个线程同时创建多份。
缺点:如果后面用不到,就浪费了资源。
懒汉模式
只有调用单例对象创建接口才真正创建出单例对象。
优点:什么时候用就什么时候创建,如果用不到则不会创建,节约资源。
缺点:如果多个线程同时调用创建接口可能会创建出多个对象。
|