对象的初始化和清理
构造函数(初始化)和析构函数(清理)
这两个函数会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理是编译器强制要我们做的事情,如果我们不提供构造和析构,编译器会提供,所提供的构造函数和析构函数都是空实现。
构造函数:在创建对象时自动调用,为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
析构函数:在对象销毁前(比如局部变量,函数结束就销毁)系统统自动调用,执行一些清理工作。
构造函数语法:类名(){}
- 构造函数,没有返回值也不写void
- 函数名与类名相同
- 构造函数可以有参数,可以发生重载
- 无需手动调用,且只会调用一次
析构函数:~类名(){}
先定义的后析构
- 没有返回值也不写void
- 函数名与类名相同,前面加上~
- 析构函数不能有参数,因此不可以发送重载
- 由编译器自动调用,无需手动调用,且只会调用一次
构造函数的分类
两种分类方式:
- 按参数分:有参构造和无参构造(默认构造函数)
- 按类型分:普通构造和拷贝构造(将一个对象的属性完全复制到另一个对象)
拷贝构造:const Person& p
–只是复制,加const可以避免改变。
Person(const Person& p) {
age = p.age;
}
三种调用方式:
- 括号法
- 显示法
- 隐式转换法
注意事项:
- 调用默认构造时,不要加()–
Person p();
编译器认为是函数的声明,不会认为在创建对象。 - 匿名对象 特点:当前行执行结束后,系统会立即回收。
Person(10);
- 不要利用拷贝构造函数 初始化匿名对象
Person(p3)
编译器认为Person(p3)==Person p3
;
#include <iostream>
using namespace std;
//按参数分:有参构造和无参构造
class Person {
public:
int age;
Person() {
cout << "无参构造函数(默认构造函数)调用" << endl;
}
Person(int a) {
age = a;
cout << "有参构造函数调用" << endl;
}
//拷贝构造函数(将一个对象的属性完全复制到另一个对象)
Person(const Person& p) {
age = p.age;
cout << "拷贝构造函数调用" << endl;
}
~Person() {
cout << "析构函数调用" << endl;
}
};
//调用
int main() {
//创建实例对象时,调用构造函数
//括号法
//Person p;//默认构造
//Person p2(10);//有参构造函数
//Person p3(p2);//拷贝构造函数
//显示法
Person p1;
Person p2 = Person(10);//有参构造函数
Person p3 = Person(p2);//拷贝构造函数
Person(10);//匿名对象 特点:当前行执行结束后,系统会立即回收。
//隐式转换法
Person p4 = 10;//Person p2 = Person(10);
return 0;
}
拷贝构造函数调用时机
三种情况:
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
void dowork( Person p) {//形参会复制出一个拷贝的副本
}
void test02() {
Person p;//默认构造
dowork(p);//调用拷贝构造函数
}
//值方式返回
Person dowork2() {
Person p1;//
return p1;//这里p1与上面的p1不一样。拷贝的p1的新的对象
}
void test03() {
//调用拷贝构造函数
Person p = dowork2();
}
构造函数的调用时机
c++编译器至少给一个类添加3个函数:
- 默认的构造(空实现)
- 默认析构(空实现)
- 默认拷贝构造函数,对属性就行值拷贝
调用规则如下:
- 如果用户定义有参构造函数,C++不在提供默认无参构造,但会提供默认拷贝构造。
- 如果用户定义拷贝构造函数,c++不会再提供其他构造函数。
深拷贝与浅拷贝
浅拷贝:监督的赋值拷贝操作 —带来问题:堆区内存重复释放。
深拷贝:在堆区重新申请空间,进行拷贝操作
自己实现以一个拷贝构造函数,解决浅拷贝带来的问题。利用深拷贝解决。
#include <iostream>
using namespace std;
class Person {
public:
int age;
int* Height;
Person() {
cout << "无参构造函数(默认构造函数)调用" << endl;
}
Person(int a) {
age = a;
cout << "有参构造函数调用" << endl;
}
Person(int a,int height) {
age = a;
Height = new int(height);
cout << "有参构造函数调用" << endl;
}
//拷贝构造函数(将一个对象的属性完全复制到另一个对象)
Person(const Person& p) {
age = p.age;
cout << "拷贝构造函数调用" << endl;
//深拷贝操作
//重新定义一块内存存储数据。
Height = new int(*p.Height);
}
~Person() {
//堆区开辟的数据提前做释放操作--由程序员手动
if (Height != NULL) {
delete Height;
Height = NULL;//防止野指针出现
}
cout << "析构函数调用" << endl;
}
};
void test01() {
Person p1(19,160);
cout << p1.age << *p1.Height<< endl;
Person p2(p1);//值拷贝,浅拷贝
cout << p2.age << *p2.Height << endl;
}
int main() {
test01();
return 0;
}
初始化列表
C++提供初始化列表语法,用来初始化属性;
语法:构造函数():属性1(值1),属性2(值2)....{}
Person(int a,int b,int c): m_A(a),m_b(b),m_c(c){
}
//实例
Person(10,20,30);