类和对象(中)

类的六个默认成员函数

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

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

拷贝构造

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

构造函数作用在于初始化对象类似于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;
}

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


日期打印

相关推荐
Bayi·6 小时前
前端面试场景题
开发语言·前端·javascript
碎梦归途6 小时前
23种设计模式-结构型模式之享元模式(Java版本)
java·开发语言·jvm·设计模式·享元模式
明月看潮生6 小时前
青少年编程与数学 02-018 C++数据结构与算法 06课题、树
数据结构·c++·算法·青少年编程·编程与数学
小指纹6 小时前
动态规划(一)【背包】
c++·算法·动态规划
Xiaoyu Wang6 小时前
Go协程的调用与原理
开发语言·后端·golang
bigear_码农6 小时前
python异步协程async调用过程图解
开发语言·python·线程·进程·协程
zhaoyqcsdn7 小时前
抽象工厂模式及其在自动驾驶中的应用举例(c++代码实现)
c++·经验分享·笔记·设计模式
天若有情6737 小时前
用 C++ 模拟 Axios 的 then 方法处理异步网络请求
网络·c++·php
知识分享小能手7 小时前
JavaScript学习教程,从入门到精通,Ajax与Node.js Web服务器开发全面指南(24)
开发语言·前端·javascript·学习·ajax·node.js·html5