类和对象(中)

类的六个默认成员函数

如果一个类中一个默认成员函数也没有那这个类我们叫作空类。

但是如果一个类中每有默认成员函数的话,会怎样呢?答案是编译器会帮我们自动实现类。

拷贝构造

构造函数是一个特殊的成员函数,函数名和类名相同没有返回值。创建类类型对象时,由编译器自动调用。并且在对象整个生命空间周期类只调用一次。

构造函数作用在于初始化对象类似于int a=1;给啊初始化为1;

我们看一下具体的代码片段:

cpp 复制代码
//重点关注注释部分
//代码是我做题通过后进行拷贝下来的代码,可以适当理解一下,题目最后放在末尾
class date {
public:
	date(int year, int month, int day , int days) //构造函数,没有返回值,但是不需要void
	{
		_year = year;
		_month = month;
		_day = day;
		_days = days;
	} 

	date(int year = 2025, int month = 4 , int day =23 , int days = 100) //函数重载《也是无参构造函数,无参构造函数一个类中只能存在一个》
	{
		_year = year;
		_month = month;
		_day = day;
		_days = days;
	} 

	int Get_month(int month)
	{
		int arr_month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month==2 && _year % 4 == 0 && _year % 100 != 0 || _year % 400 == 0)
		{
			arr_month[2] = 29;
		}
		return arr_month[month];
	}

	date datecount()
	{
		int i = Get_month(_month);
		_days += _day;
		while (_days > i)
		{
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
			_days -= i;
			i= Get_month(_month);
		}
		_day = _days;
		return *this;
	}

	void Print()
	{
		//打印年
		cout << _year << "-";
		//打印月份
		if (_month < 10)
		{
			cout << 0 << _month << "-";
		}
		else
			cout << _month << "-";
		//打印日
		if (_day < 10)
		{
			cout << 0 << _day << endl;
		}
		else
			cout << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
	int _days;
};


int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int year, month, day;
		int days;
		cin >> year >> month >> day >> days;
		date a(year, month, day, days); //编译器自动调用构造函数,用来初始化对象。
		a.datecount().Print();
		//日期打印
		
	}

	return 0;
}

还有一点是,构造函数跟其他成员函数一样可支持重载。

你可能会问,如果我没有写构造函数会怎样?

这个时候编译器就会有自己的想法,编译器会自己生成一个无参的构造函数,并进行调用。但是这有时候我们并不知道编译器构造的成员函数是怎样的,不知道是否能正确的完成初始。所以在C++11中打了一个补丁。即在内置类型成员变量在类中声明时可以给默认值

cpp 复制代码
private:
	int _year =  2025;  //这时声明不是初始化
	int _month = 4;		//这时声明不是初始化
	int _day = 23;		//这时声明不是初始化
	int _days = 24;		//这时声明不是初始化

析构函数

析构函数 也是一个特殊的成员函数,函数名和类名前加一个 ~ 符号 ,同样没有返回值,也不需要写 void

它的作用是:在对象生命周期结束时自动调用,用来进行清理工作,比如释放内存、关闭文件、断开网络连接等。

基本格式:

cpp 复制代码
~类名()
{
    // 清理操作
}

对于这段日期代码来说,我们的类中没有使用 new 动态分配内存,因此不写析构函数也没关系,编译器会默认生成一个"空析构函数"。

但出于规范,我们可以手动写一个出来作为示例:

cpp 复制代码
class date {
public:
    // 构造函数略

    ~date()
    {
        // 目前这个类没有资源需要手动释放
        // 这里只是说明析构函数的位置
        cout << "析构函数被调用,日期对象被销毁" << endl;
    }

    // 其他成员函数略

private:
    int _year;
    int _month;
    int _day;
    int _days;
};

注意事项:

  • 析构函数不能有参数、不能被重载
  • 如果类中有用 new 申请了堆空间(如 int* p = new int),必须写析构函数释放资源,否则会内存泄漏。
  • 析构函数通常不需要手动调用,在对象生命周期结束时自动调用

示例输出位置:

main() 函数中执行完这一行:

cpp 复制代码
date a(year, month, day, days);

对象 a 在这个作用域结束时就会被销毁,自动调用析构函数。为了验证我们可以加入一段测试:

cpp 复制代码
int main()
{
    {
        date a(2025, 4, 23, 100);
        a.datecount().Print();
    } // 在这个大括号结束的位置,a 被销毁,会调用析构函数
    return 0;
}

运行时会输出:

复制代码
2025-08-01
析构函数被调用,日期对象被销毁

小结

函数 特点 何时调用
构造函数 用于初始化对象 创建对象时
析构函数 用于清理资源 销毁对象时

你可以简单记住它们是"出生与销毁"这一对搭档。

拷贝构造函数

拷贝构造函数用于创建一个新对象,并用一个已有对象进行初始化。

格式:

cpp 复制代码
date(const date& d)
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
    _days = d._days;
    cout << "调用拷贝构造函数" << endl;
}

特点:

  • 参数是一个同类对象的引用 ,并且通常加上 const
  • 如果不写,编译器会默认生成一个"浅拷贝"的拷贝构造函数。

示例:

cpp 复制代码
date d1(2025, 4, 23, 100);
date d2 = d1; // 调用拷贝构造函数

当我们传值或返回对象时,也可能调用拷贝构造:

cpp 复制代码
date foo(date d) // 这里传值会调用拷贝构造
{
    return d;    // 返回也可能触发拷贝
}

赋值运算符重载

用于对象赋值,即:一个已经存在的对象被另一个对象赋值。

格式:

cpp 复制代码
date& operator=(const date& d)
{
    if (this != &d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
        _days = d._days;
    }
    cout << "调用赋值运算符重载" << endl;
    return *this;
}

注意:

  • 需要返回 *this 的引用 ,以支持链式赋值 a = b = c;
  • 自赋值检查很重要:if (this != &d)
  • 如果类中有资源分配(如 new),一定要手动写赋值运算符重载,避免浅拷贝问题。

const 成员函数

cpp 复制代码
void Print() const
{
    cout << _year << "-" << _month << "-" << _day << endl;
}

特点:

  • 在函数后加 const 表示这个函数不会修改对象的成员变量
  • 只能调用其他 const 成员函数。
  • 常用于 const 对象,如:
cpp 复制代码
const date d(2025, 4, 23, 100);
d.Print(); // 只能调用 const 函数

取地址及 const 取地址操作符重载

普通取地址:

cpp 复制代码
date* operator&()
{
    cout << "调用取地址操作符&" << endl;
    return this;
}

const 取地址:

cpp 复制代码
const date* operator&() const
{
    cout << "调用 const 取地址操作符&" << endl;
    return this;
}

这两个可以帮助我们在调试或做特殊封装时了解对象的地址行为。


日期打印

相关推荐
运维管理5 分钟前
Linux系统笔记--Base
开发语言·php
全栈软件开发35 分钟前
最新版T5友价互站网源码商城PHP源码交易平台 完整带手机版源码网系统源码
android·开发语言·php
Mos_x36 分钟前
关于我们的python日记本
开发语言·python
The Sheep 202343 分钟前
Dotnet-Dapper的用法
java·开发语言
马克学长1 小时前
SSM基于Java的医疗器械销售系统oy281(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·开发语言·用户管理·ssm 框架·医疗器械销售系统
apocelipes1 小时前
C++ Two Phase Lookup导致的模板代码编译错误
c++·泛型编程
lqj_本人1 小时前
Rust与Go:现代系统编程语言的深度对比
开发语言·golang·rust
hansang_IR2 小时前
【题解】洛谷 P1477 [NOI2008] 假面舞会 [思维 + 图论]
c++·算法·图论·思维
星释2 小时前
Rust 练习册 :Macros与宏系统
开发语言·后端·rust
l1t2 小时前
利用短整数类型和部分字符串优化DuckDB利用数组求解数独SQL
开发语言·数据库·sql·duckdb