对象的初始化和清理是两个非常重要的安全问题:
一个对象或者变量没有初始状态,对其使用后果是未知的。
同样的使用完一个对象或者变量,没有及时清理,也会造成一定的安全问题。
c++利用构造函数和析构函数解决上述问题。
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
构造函数语法: 类名(){}
1.构造函数,没有返回值也不写void。
2.函数名称与类名相同。
3.构造函数可以有参数,因此可以发生重载。
4.程序在调用对象时候自动调用构造,无需手动调用,而且只会调用一次。
析构函数语法:~类名(){}
1.析构函数没有返回值,也不写void。
2.函数名称与类名相同,在名称前面加上符号~。
3.析构函数不可以有参数,因此不可以发生重载。
4.程序在销毁对象前自动调用析构,无需手动调用,而且只会调用一次。
构造函数的分类及调用
两种分类方式:
按参数分:有参构造和无参(默认)构造。
按类型分:普通构造和拷贝构造。
拷贝构造:
类名(const 类名 & 对象名)
例子:
person(const person& p)
{
}
三种调用方式:
1.括号法
例子:
person p; //默认构造函数的调用
person p1(10); //有参构造函数的调用
person p3(p1); //拷贝构造函数的调用
注意:
调用默认(无参)构造函数时候,不要加(),因为编译器会认为是一个函数的声明,不会认为在创建对象。
2.显示法
匿名对象 特点:当前行执行结束后,系统会立即回收掉匿名对象。
注意:
不要利用拷贝构造函数 初始化匿名对象 编译器会认为这是对象的声明。
比如:person p3 = person(p2); //拷贝构造 person(p3);
编译器会认为 person(p3) ==person p3
3.隐式转换法
例子:
person p4 = 10; //有参构造函数调用 等价与 person p4=person(10)
person p5 = p4; //拷贝构造函数的调用
拷贝构造函数调用时机
1.使用一个已经创建完毕的对象来初始化一个新对象。
2.值传递的方式给函数参数传值。
3.以值的方式返回局部对象。
构造函数的调用规则:
创建一个类,c++编译器会给每个类都添加至少3个函数。
1.默认构造函数(无参,函数体为空)。
2.默认析构函数(无参,函数体为空)。
3.默认拷贝构造函数,对属性进行值拷贝。
构造函数调用规则:
1.如果用户定义有参构造函数,c++不再提供默认无参构造,但是会提供默认拷贝构造。
2.如果用会定义拷贝构造函数,c++不再提供其他构造函数。
深拷贝与浅拷贝
浅拷贝:简单的复制拷贝操作。
深拷贝:在堆区重新申请空间,进行拷贝操作。
浅拷贝带来的问题是队取得内存重复释放。
所以,如果有属性在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。
初始化列表
语法:构造函数():属性1(值1),属性2(值2).......{}
括号里可以加形参
例子:
person(int a,int b,int c):m_a(a),m_b(b),m_c(c)
{
}
类对象作为类成员
c++类中的成员可以是另一个类的对象,我们称该成员为 对象成员。
当其它类对象作为本类对象,构造时候先构造其它类对象,在构造自身,析构顺序与构造相反。
静态成员
静态成员就是在成员变量和函数前加上关键字static,称为静态成员。
静态成员变量:
1.所有对象共享同一份数据
2.在编译阶段分配内存
3.类内声明,类外初始化
静态成员变量有两种访问方式:
1.通过对象进行访问
person p;
cout << p.a << endl;
2.通过类名进行访问
cout << person::a << endl;
静态成员变量也有访问权限
类外初始化操作
例子:
int person::a = 1000;
静态成员函数:
1.所有对象共享同一个函数
2.静态成员函数只能访问静态成员变量
1.通过对象来访问
2.通过类名来访问