【C++核心编程 4】——类和对象——4.2 对象的初始化和清理[ 4.2.1-4.2.4 构造函数 / 析构函数 ]

4.类和对象

C++面向对象的三大特性:封装、继承、多态

C++认为万事万物都皆为对象,对象上有其属性和行为


具有相同性质的对象,可以抽象为


4.2 对象的初始化和清理

C++的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置


4.2.1 构造函数和析构函数

对象的初始化清理是两个非常重要的安全问题。

​ 一个对象或者变量没有初始状态,对其使用后果是未知的。

​ 使用完一个对象或变量,没有及时清理,也会造成一定的安全问题。


C++利用了构造函数析构函数解决上述问题,两个函数将会被编译器自动调用,完成对象初始化和清理工作。

对象的初始化和清理工作是编译器强制要求我们做的事情,如果我们不提供析构函数和构造函数,编译器会提供,编译器所提供的构造函数和析构函数是空实现(即什么内容都没有)。


  • 构造函数:主要作用在创建对象时为对象的成员属性赋值,构造函数有编译器自动调用,无需手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

– 构造函数语法:

类名(){}

  1. 构造函数,没有返回值,也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时会自动调用构造,无需手动调用,且只会调用一次
– 析构函数语法:

~类名(){}

  1. 析构函数,没有返回值,也不写void
  2. 函数名称与类名相同,在名称前加上符号 ~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构函数,无需手动调用,且只会调用一次
#include<iostream>
using namespace std;
//对象的初始化与清理
//构造函数初始化对象   析构函数清理对象
class Person {
public:
	//构造函数
	Person() {
		cout << "调用构造函数" << endl;
	}

	~Person() {
		cout << "调用析构函数" << endl;
	}
};
int main() {
	Person p;

	return 0;
}

4.2.2 构造函数的分类及调用

两种分类方式:

  • 按参数分为:有参构造 和 无参构造(默认构造)
  • 按类型分为:普通构造 和 拷贝构造

三种调用方式: 括号法、显式法、隐式转换法

#include<iostream>
using namespace std;
//对象的初始化与清理
//构造函数初始化对象   析构函数清理对象
class Person {
public:
	//构造函数
	Person() {
		cout << "Person的无参构造函数调用" << endl;
	}

	Person(int a) {
		age = a;
		cout << "Person的有参构造函数调用" << endl;
	}

	//拷贝构造函数
	Person(const Person &p) {
		//将传入的对象身上的所有属性,拷贝到自己身上
		age = p.age;
		cout << "Person的拷贝构造函数调用"  << endl;
	}
  //析构函数
	~Person() {
		cout << "调用析构函数" << endl;
	}

	int age;
};
//调用
void test01(){
  Person p;//调用无参构造函数  普通调用方法
}
void test02() {
	//1.括号法
	Person p1;//默认(无参)构造函数的调用
	Person p2(12);//有参构造函数的调用
	Person p3(p2);//拷贝构造函数的调用,将p2拷贝到p3

	//注意事项:调用默认构造函数时,不要加(),因为Person p1();会被编译器认为是一个函数的声明
	
	//cout << "p2的年龄:" << p2.age << endl;//12
	//cout << "p3的年龄:" << p3.age << endl;//12
	
  //2.显式法
	Person p1;
	Person p2 = Person(10);//显式的调用有参构造
	Person p3 = Person(p2);//拷贝构造

	Person(11);//匿名对象,左侧没有命名,特点:当前行执行结束后,系统会立即回收掉匿名对象,即马上析构

	//注意事项:
	// 不要利用拷贝构造函数 初始化匿名对象,编译器会认为Person (p3)等价于 Person p3,会认为Person (p3)是一个对象的声明
  
  	//3.隐式转换法
	Person p2 = 10;//相当于 Person p2 = Person(10); 有参构造
	Person p3 = p2;//相当于 Person p3 = Person(p2); 拷贝构造
}
int main() {
	test02();

	return 0;
}

4.2.3 拷贝构造函数调用时机

C++中拷贝构造函数调用时机通常有3种情况

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象
#include<iostream>
using namespace std;

class Person {
public:
	Person() {
		cout << "无参构造函数" << endl;
	}
	Person(int age) {
		cout << "有参构造函数" << endl;
		m_age = age;
	}
	Person(const Person& p) {
		cout << "拷贝构造函数" << endl;
		m_age = p.m_age;
	}

	~Person() {
		cout << "析构函数调用" << endl;
	}
	int m_age;
};
//使用一个已经创建完毕的对象来初始化一个新对象
void test01() {
	Person p1(20);//调用有参
	Person p2(p1);//调用拷贝
	cout << "p2的年龄:" << p2.m_age << endl;
}
//值传递的方式给函数参数传值
void doWork(Person p) {

}
void test02() {
	Person p;
	doWork(p);//值传递,复制出一个临时的副本
}

//以值方式返回局部对象
Person dowork2() {
	Person p;
	cout << (int*)&p << endl;
	return p;//返回时,根据p创建一个新的对象,然后进行返回
}//局部对象在函数执行完之后就会被释放掉
void test03() {
	Person p3 = dowork2();
	cout << (int*)&p3 << endl;//两次地址不同,说明返回的是新的对象
}
int main() {
	/*test01();*/
	/*test02();*/
	test03();
	return 0;
}

4.2.4 构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则如下:

  • 如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造。
  • 如果用户定义拷贝构造函数,C++不会再提供其他构造函数。

示例:

#include<iostream>
using namespace std;
//1.创建一个类,默认情况下,C++编译器至少给一个类添加3个函数
//默认构造(空实现)
//析构函数(空实现)
//拷贝构造(值拷贝)
class Person {
 public:
	Person() {
		cout << "Person的默认构造函数调用" << endl;
	}
	Person(int age) {
		cout << "Person的有参构造函数调用" << endl;
		m_age = age;
	}
/*	Person(const Person& p) {
		cout << "Person的拷贝构造函数调用" << endl;
		m_age = p.m_age;
	}
	*/

	~Person() {
		cout << "Person的析构函数调用" << endl;
	}
	int m_age;
};

void test01() {
	Person p;//默认构造
	p.m_age = 18;
	Person p2(p);//拷贝构造,当没有拷贝构造函数时,编译器会默认添加一个拷贝构造函数 进行值传递
	cout << "p2的年龄:" << p2.m_age << endl;//18
}
int main() {
	test01();
	return 0;
}
#include<iostream>
using namespace std;
//2.当我们写了有参构造函数,编译器就不再提供默认构造函数,但依然提供拷贝构造
class Person {
 public:
	//Person() {
	//	cout << "Person的默认构造函数调用" << endl;
	//}
	//Person(int age) {
	//	cout << "Person的有参构造函数调用" << endl;
	//	m_age = age;
	//}
	Person(const Person& p) {
		cout << "Person的拷贝构造函数调用" << endl;
		m_age = p.m_age;
	}

	~Person() {
		cout << "Person的析构函数调用" << endl;
	}
	int m_age;
};

void test02() {
  //Person p;//报错,此时编译器不再提供默认构造函数
	Person p3(28);//有参构造
	Person p4(p3);//拷贝构造
	cout << "p4的年龄:" << p4.m_age << endl;//28
}
int main() {
	test02();
	return 0;
}
#include<iostream>
using namespace std;
//3.如果写了拷贝构造函数,编译器就不再提供其他普通构造函数
class Person {
 public:
	Person(const Person& p) {
		cout << "Person的拷贝构造函数调用" << endl;
		m_age = p.m_age;
	}

	~Person() {
		cout << "Person的析构函数调用" << endl;
	}
	int m_age;
};

void test03() {
	Person p;//报错,此时编译器不再提供默认构造函数
	Person p2(30);//报错,此时编译器不再提供有参构造函数
}
int main() {
	test03();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值