C++----默认成员函数

本文深入解析C++中的构造函数、析构函数、拷贝构造、赋值运算符重载等概念,阐述它们的功能、特性和使用场景,帮助读者理解对象初始化与资源清理的机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造函数

        构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有初始值,并且在对象的生命周期内只调用一次。它并不开空间创建对象,而是初始化对象。

  1. 特性:
#include<iostream>
using namespace std;
class Date {
private:
	int _years, _month, _day;
public:
	Date(int year, int month, int day) {  //构造函数,创建类类型对象时由编译器自动调用,不能和全缺省三个参数共存
		_years = year;
		_month = month;
		_day = day;  //没有返回值
	}
	Date() {  //可重载,但调用上有歧义且不能和全缺省三个参数共存
		_years = 2020;
		_month = 2;
		_day = 2;
	}
	Date(int year) {  //可缺省
		_years = year;
		_month = 3;
		_day = 3;
	}
	void Init(int year, int month, int day) {  //有构造函数就无需再初始化了
		_years = year;
		_month = month;
		_day = day;
	}
	void Print() {
		cout << _years << "-" << _month << "-" << _day << endl;
	}
};
int main() {
	Date d1(2010, 10, 10);  //并不是开空间创建对象,而是初始化对象
	d1.Print();
	//Date d1(2010, 10, 10);  无法二次调用
	Date d2;  //可重载,没有参数不能加"()"
	d2.Print();
	Date d3(2020);  //缺参数
	d3.Print();
	d2.Init(2010, 12, 06);
	d2.Print();
	system("pause");
	return 0;
}

在这里插入图片描述
        2. 全缺省构造:(最常用)

#include<iostream>
using namespace std;
class Date {
private:
	int _years, _month, _day;
public:
	Date(int year = 2019, int month = 9, int day = 9) {
		_years = year;
		_month = month;
		_day = day;
	};
	void Print() {
		cout << _years << "-" << _month << "-" << _day << endl;
	};
};
int main() {
	Date d1;  
	Date d2(2020); 
	Date d3(2020,2);
	Date d4(2020, 2, 2);
	d1.Print();
	d2.Print();
	d3.Print();
	d4.Print();
	return 0;
}

在这里插入图片描述
        3. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语法已经定义好的类型:如int/char…,自定义类型就是我们使用class/struct/union自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。

析构函数

        与构造函数功能相反,析构函数负责清理而不是完成对象的销毁,对象销毁工作是由系统完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。

  1. 特性:
#include <iostream>
using namespace std;
class Date {
public:
	Date(int year = 2020, int month = 2, int day = 2) {
		_year = year;
		_month = month;
		_day = day;
	}
	~Date() {}  //Date类没有资源需要清理,所以析构函数类什么都不用写
	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
class Stack {
public:
	Stack(int n = 10) {
		_a = (int*)malloc(sizeof(int)*n);
		_size = 0;
		_capacity = n;
	}
	~Stack() {  //Stack不写析构,会内存泄漏
		free(_a);
		_size = _capacity = 0;
		_a = nullptr;
	}
private:
	int* _a;
	int _size;
	int _capacity;
};
int main() {
	Date d1;
	d1.Print();
	Stack st(100);  //C++类使用构造函数和析构函数来解决忽视初始化和清理问题
	return 0;
}
  1. 默认析构:
#include <iostream>
using namespace std;
class Time {
public:
	~Time() {
		cout << "~Time()" << endl;
	}
};
class Date {
public:
	Date(int year = 2020, int month = 2, int day = 2) {
		_year = year;
		_month = month;
		_day = day;
	}	
	void Print() {  //内置类型不处理,但要处理自定义类型,调用它Time的析构函数
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
int main() {
	Date d;
	d.Print();
	system("pause");
	return 0;
}

注: 先构造的后析构(栈帧),先局部后全局。

拷贝构造

        拷贝构造函数是构造函数的一个重载形式。拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝。

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 2020, int month =2, int day = 2) {
		_year = year;
		_month = month;
		_day = day;
	}
	//Date copy(d1);  无穷递归
	Date(const Date& d) {
  		_year = d._year;
		_month = d._month;
		_day = d._day;
 }
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;	
	Date d2(d1);  //这里d2调用的默认拷贝构造完成拷贝,d2和d1的值也是一样的。
	return 0;
}
赋值运算符重载
运算符重载

        C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
        函数名字为:operator[操作符];
        函数原型:返回值类型 operator[操作符] (参数列表)
        5个不能重载的运算符: .* 、::sizeof?: .  。

#include <iostream>
using namespace std;
class Date {
public:
	int _year;
	int _month;
	int _day;
	Date(int year = 2020, int month = 2, int day = 2) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
};
 //参数为自定义类型的对象传参尽量用引用,提高效率
bool CompareEquelDate(const Date& d1, const Date& d2) {  //bool型,真则返回1否则为0
	return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
bool operator>(const Date& d1, const Date& d2) {  //C++解决方式:运算符重载,可读性比较强
	return d1._year > d2._year || d1._month > d2._month || d1._day > d2._day;
}
bool operator==(const Date& d1, const Date& d2) {  
	return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
bool operator<(const Date& d1, const Date& d2) { 
	return d1._year < d2._year || d1._month < d2._month || d1._day < d2._day;
}
int main() {
	Date d1(2020, 3, 13);
	Date d2(2020, 3, 12);
	Date d3(2020, 3, 14);
	cout << CompareEquelDate(d1, d2) << endl;
	cout << operator==(d1, d2) << endl;  //一般不这么用,没有可读性
	cout << (d1 == d2) << endl;  //0,编译遇到d1==d2会转化成operator==(d1,d2)
	cout << (d1 > d2) << endl;  //1
	cout << (d3 < d2) << endl;  //0
	//运算符重载的意义是,可以让自定义类型像内置类型一样去使用我们的运算符,增强程序的可读性
	return 0;
}
赋值运算符

        与处理拷贝构造函数一样,如果一个类没有定义自己了拷贝赋值运算符,则编译器会为它生成一个合成拷贝赋值运算符。类似拷贝构造函数,对于某些类,合成拷贝赋值运算符用来禁止该类型对象的赋值。如果拷贝赋值运算符并非出于此目的,它会将右侧运算对象的每个非static成员赋予左侧运算对象的对应成员,这一工作是通过成员类型的拷贝赋值运算符来完成的。对于数组类型的成员,逐个赋值数组元素。合成拷贝赋值运算符返回一个指向其左侧运算对象的引用。
特点: 参数类型,返回值,检查自身赋值,返回*this

#include<iostream>
using namespace std;
class Date {
public:
	Date(int year = 1900, int month = 1, int day = 1) {
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d) {
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	Date& operator=(const Date& d) {
		if (this != &d){
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
	}
private:
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1;
	Date d2(2019, 2, 20);  //这里d1调用的编译器生成operator=完成拷贝,d2和d1的值也是一样的。
	Date d3 = d2;  //注意:直接调用拷贝构造而不是调用operator
	d1 = d2;
	return 0;
}
const成员

        将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

#include<iostream>
using namespace std;
class Date {
public:
	/*void Display() {
		cout << "Display ()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}*/
	void Display() const {  //在成员函数内保护调用对象不被修改	
		cout << "Display () const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main() {
	Date d1;
	d1.Display();
	const Date d2;
	d2.Display();
}
  1. const对象和成员函数都不可以调用非const成员函数吗;
  2. 非const对象和成员函数都可以调用const成员函数吗。
    const Date* -->const Date*
    Date* -->Date*
    Date* -->const Date*
    const Date* -X>Date*

取地址及const取地址操作符重载: 这两个默认成员函数一般不用重新定义 ,编译器默认会生成
只有在想让他人获取到指定的内容时才使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值