c++类和对象(四)

༺ 个人主页 · 纪念229 ༻

🏠我的博客主页🏠

༒专栏目录:《数据结构》༒

༒专栏目录:《算法》༒

༒专栏目录:《C++》༒

༒专栏目录:《MySQL数据库》༒

༒专栏目录:《前端开发》༒

༒其它有趣的计算机知识༒

༺世上本没有路,走的人多了自然就有了༻


本篇文章续接上文讲述类和对象代码的讲解,补充了Test.cpp上的代码,多加了两个头文件的代码(利用运算符重载实现日期的一些功能),希望对你有所帮助


文章目录


代码展示

Test.cpp

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;
//
//class Date
//{
//public:
//	//全缺省默认形参从右往左弄
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		cout << "Date(int year = 1, int month = 1, int day)" << endl;
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//	//拷贝构造函数
//	// 当形参与传入的实参不是一个东西的时候就会调用拷贝构造
//	// 这种情况是函数的形参没用引用导致递归是错误写法
//	//d2(d1)
//	Date(const Date& d)
//	{
//		_year = d._year;
//		_month = d._month;
//		_day = d._day;
//	}
//
//	Date(Date* d)
//	{
//		_year = d->_year;
//		_month = d->_month;
//		_day = d->_day;
//	}
//
//	~Date()
//	{
//		cout << "~Date()" << endl;
//	}
//
//
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//
//
//typedef int STDataType;
//class Stack
//{
//public:
//	Stack(int n = 4)
//{
//		_a = (STDataType*)malloc(sizeof(STDataType) * n);
//		if (nullptr == _a)
//		{
//			perror("malloc fail");
//			return;
//		}
//		_capacity = n;
//		_top = 0;
//
//}
//	//st2(st1)
//	Stack(const Stack& s)
//	{
//		cout << "Stack(const Stack& s)" << endl;
//		_a = (STDataType*)malloc(sizeof(STDataType) * s._capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc fail");
//			return;
//		}
//		_top = s._top;
//		_capacity = s._capacity;
//	}
//
//	void Push(const STDataType& x)
//	{
//		//.扩容
//		_a[_top] = x;
//		_top++;
//	}
//
//	int Top()
//	{
//		return _a[_top - 1];
//	}
//	~Stack()
//	{
//		cout << "~Stack()" << endl;
//		free(_a);
//		_a = nullptr;
//		_top = _capacity = 0;
//	}
//private:
//	STDataType* _a;
//	int _top;
//	int _capacity;
//};


//class Myqueue
//{
//private:
//	Stack pushst;
//	Stack popst;
//};
//
//
//
//
//void func(Date& d)
//{
//
//}
//
////对象在main函数生成main是栈里的一个栈帧
////所以对象不会消失,实例化的调用构造函数结束后
////对象类变量还在
////int main()
////{
////	Date d1(2025, 4, 24);//构造
////	Date d2(d1);//拷贝构造
////	Date d4 = d1;//拷贝构造
////
////	Date d3(&d1);//构造
////	Date d5 = &d1;//构造
////
////	//Date d4 = d1;//拷贝构造
////	//Date d5 = &d1;//构造
////	//这里的= 不是赋值是类的实例化
////	//传了一个实参根据类型比对普通构造还是拷贝构造
////	//类的实例化实际后自动调用的实际上是构造函数或者拷贝构造
////	//具体看的是传的实参
////	//类实例化传实参的方式有两种
////	//Date d3(&d1);//构造
////	//Date d5 = &d1;//构造在类变量一行=不是赋值是实例化传参
////	
////	func(d1);
////	return 0;
////}
//
//
//
//int main()
//{
//	Stack st1;
//	st1.Push(1);
//	st1.Push(2);
//	st1.Push(3);
//	st1.Push(4);
//
//	Stack st2(st1);
//
//	Date d1(2025, 4, 24);
//	Date d2(d1);
//
//	Myqueue q1;
//	//类里没写拷贝构造调用会自动用默认拷贝函数
//	//将引用对象的值给新对象
//	Myqueue q2(q1);
//	return 0;
//}

//int& f1()
//int f1()
//{
//	int ret = 0;
//	return ret;
//}
//
////Stack& f2()
//Stack f2()
//{
//	Stack st;
//	st.Push(1);
//	st.Push(2);
//	st.Push(3);
//   
//	return st;
//}
//
//int main()
//{
//	cout << f1() << endl;
//
//	cout << f2().Top() << endl;
//	//当我们调试时会发现调试器会把st看成地址所以我们用st->_a, 3 看_a里面的东西
//	return 0;
//}

//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;
//		_year = year;
//		_month = month;
//		_day = day;
//	}
////private:
//	int _year;
//	int _month;
//	int _day;
//};
//
////1.提供Getxxx函数
////2.友元
////3.直接放到类里面
//
//bool operator==(const Date& x1, const Date& x2)
//{
//	cout << "我TM来了";
//		return x1._year == x2._year
//		&& x1._month == x2._month
//		&& x1._day == x2._day; 
//}
////运算符重载是特殊函数,当使用该运算符,且运算符两边类型匹配形参类型时
////编译器就会自动调用这个重载函数
////这里我们的形参是两个类类型
//int main()
//{
//	int i = 1, j = 2;
//	//bool ret1 = i < j;
//	cout << (i < j) << endl;
//
//	i++;
//
//	const Date d1(2025, 4, 25);
//	const Date d2(2025, 4, 26);
//	//bool ret2 = d1 == d2;
//	//cout << (d1 == d2) << endl;
//	//operator==(d1, d2);
//
//	Date d3(2025, 4, 25);
//	Date d4(2025, 3, 26);
//
//	cout << (d3 == d4) << endl;
//
//	return 0;
//}
//////////////////////////////////////
//class Date
//{
//public:
// 
//	Date(int year, int month, int day)
//	{
//		cout << "Date(int year, int month, int day)" << endl;
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	bool operator==(const Date& d)
//	{
//		return _year == d._year
//			&& _month == d._month
//			&& _day == d._day;
//	}
//	//这里的运算符重载与之前的运算符重载函数没啥区别
//	//就是只有调用这个对象才能使用运算符重载
//
//
//	//日期减日期(相差天数)有意义
//	//int作为返回值我们称日期
//	//作为形参我们称整数在这里
//	int operator-(const Date& d);
//
//	//这里的类会隐式类型转换成int
//	//Date d1(2025,4,23)
//	//转化为int d1 2025423
//
//	//语法上可以
//	//日期加日期实践上没意义
//
//	//int operator+(const Date& d);
//
//	//日期加整数有意义
//	//Date operator+(int day);
//private:
//	int _year;
//	int _month;
//	int _day;
//};
// 类只有写拷贝构造才能与其它类或同类加减乘除比大小
////运算符重载和sizeof不要头文件
////int operator+(int x, int y);
//
//这个报错的原因是运算符重载函数有两个形参时必须要有一个自定义形参(类 / 枚举)
// 如果运算符重载只有一个形参时(运算符重载函数在类里面)形参随便 但是调用运算符重载的函数必须是类
//
//class A
//{
//public:
//	void func()
//	{
//		cout << "A::func()";
//	}
//};
//
//
//void f()
//{
//	cout << "f()" << endl;
//}
//
//
//int main()
//{
//	//函数指针
//	//普通函数指针
//	void(*func1)() = f;
//	//在c语言和c++中只有普通全局函数名就会把函数名隐式转换为函数指针(*void)
//	// 看此题它的返回内型还是不变的
//	// void(*func1)() = f;
//	// void(*func1)() = (*f)(void类型);
//	//这里讲一下加括号与不加括号的区别
//	//void(*func1)() = f;//这个是返回void的函数指针
//	//void*func1() = f;//这个是返回void*指针的函数
//	//(*func1)//说明它是函数指针
//	//这里 = f意思是将f函数的功能给予(*func1)函数指针
//	//这里
//	(*func1)();
//	//这里也不用看解引用就把它看成要使用的函数即可(其实就是函数指针解引用调用后的函数)
//	//调用直接函数名加()即可
//
//	//类的成员函数指针
//	//类的成员函数名无法隐式转换为函数指针要在函数名加&类名::(这个指的就是类函数的函数指针)
//	void(A:: * func2)() = &A::func;
//	A aa;
//	//这里的函数指针要在对象里用才行
//	//成员函数调用
//	(aa.*func2)();
//	//这里我们会有疑问void(*func1)() = f;
//	//void(A::*func2)() = &A::func;
//	//这里的*是指针还是解引用
//	//还有就是在C++中&什么时候是引用什么时候是
//	//这里我说一下在类型一边的*是指针&是引用不管有没有括号
//	// 不在类型边的*是解引用&是取地址符号
//	//
//	//
//
//	//Date d3(2025, 4, 25);
//	//为啥不能调用(访问)因为类中的函数没加public
//	//默认就是private中的没访问限定public类中定义的函数在类外都用不了
//
//
//	Date d3(2025, 4, 25);
//	Date d4(2025, 4, 26);
//
//	cout << (d3 == d4) << endl;
//	cout << d3.operator==(d4) << endl;
//	return 0;
//}


#include"Date.h"
//写了头文件,头文件里的所有东西在编译前都会替换到这一行
//如果头文件里有函数定义那么就调用,如果没有调用处必须要有函数声明,
//最后靠链接器把其它地方对应该声明的函数定义调用过来,但是,其它地方的
//函数声明上面必须要有对应的头文件
int main()
{
	Date d1(2025, 4, 24);
	//Date d2(d1 + 100);
	Date d2 = d1 + 100;
	d1.Print();
	d2.Print();

	Date d3 = d1 += 100;
	d1.Print();
	d3.Print();
	return 0;
 }

Date.h

c 复制代码
#pragma once
#include<cassert>
#include<iostream>
using namespace std;

class Date
{
public:
	//获取对应月份的天数
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		//分平年润年来确定二月天数,一般是平年
		static int monthDayArray[13] = {
			-1, 31, 28, 31, 30, 31, 30, 31, 31, 30 ,31,
			30, 31
		};
		//这里讲一下static
		//在全局函数里做静态函数其它文件就不能调用它
		//这里的static在函数里做静态变量只有这个函数可以调用它
		
		//判断是否是闰年(判断二月有几天的方式)
		//年份能被4整除不能被100整除或能被400整除都是闰年(被整除用的是% == 0))
		//这里&&优先级高于||要把(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
		//括起来否则就会解析为if ((month == 2 && (year % 4 == 0 && year % 100 != 0)) || year % 400 == 0)
		//条件就会变成只要能被4整除就是闰年(错误)
		if(month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
		{
			return 29;
		}
		else {
			return monthDayArray[month];
		}

	}
	void Print();

	Date(int year = 1, int month = 1, int day = 1);
	Date& operator+=(int day);
	Date operator+(int day);
	Date& operator-=(int day);

	//-
	Date operator-(int day);

	//-
	int operator-(const Date& d);

	bool operator==(const Date& d);
	bool operator<(const Date& d);
	bool operator>(const Date& d);
	//...

	//++d1;
	Date operator++();
	//d1++;
	//Date operator++();
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"

void Date::Print()
{
	cout << _year << "/" << _month << "/" << _day
		<< endl;
}
//构造函数是没有返回类型的
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

//d1 += 100
Date& Date::operator +=(int day)
{
	_day += day;
	//进位
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			_month = 1;
			++_year;
		}
	}
	return *this;
}



//d1 + 100
//这里是类函数中的运算符重载函数
//只有类才能调用运算符重载函数
Date Date::operator+(int day)
{
	//Date tmp(_year, _month, _day);
	//这里类中没写拷贝构造函数,是默认的拷贝构造函数
	//可以实现拷贝类
	Date tmp(*this);
	tmp._day += day;
	//大于该月最大天数要进位
	while (tmp._day > GetMonthDay(_year, _month))
	{
		tmp._day -= GetMonthDay(_year, _month);
		++tmp._month;
		if (tmp._month == 13)
		{
			tmp._month = 1;
			tmp._year++;
		}
	}
	return tmp;
}

1.Test.c(接上回代码讲解)

c 复制代码
//int main()
//{
//	Stack st1;
//	st1.Push(1);
//	st1.Push(2);
//	st1.Push(3);
//	st1.Push(4);
//
//	Stack st2(st1);
//
//	Date d1(2025, 4, 24);
//	Date d2(d1);
//
//	Myqueue q1;
//	//类里没写拷贝构造调用会自动用默认拷贝函数
//	//将引用对象的值给新对象
//	Myqueue q2(q1);
//	return 0;
//}

拷贝构造函数上篇讲过我就不赘述了,这里讲个默认拷贝构造函数

当类没有定义拷贝构造函数却调用了拷贝构造函数就会触发默认拷贝构造(条件是拷贝的母本的类变量及其类变量的成员(递归)没有指针类型)(要想成员有指针必须在拷贝构造给指针创造空间)

c 复制代码
//	Myqueue q1;
//	//类里没写拷贝构造调用会自动用默认拷贝函数
//	//将引用对象的值给新对象
//	Myqueue q2(q1);

这个Myqueue类没写拷贝构造使用模拟默认拷贝构造将两个Stack类拷贝下来所以我们还要继续看Stack的成员发现有个int*的成员,我们看到Myqueue类里有

c 复制代码
//Stack pushst;
//	Stack popst;

即会调用构造函数这个类的构造函数给int*类型创造了空间即合理即此次默认拷贝函数合理

c 复制代码
//int& f1()
//int f1()
//{
//	int ret = 0;
//	return ret;
//}
//
////Stack& f2()
//Stack f2()
//{
//	Stack st;
//	st.Push(1);
//	st.Push(2);
//	st.Push(3);
//   
//	return st;
//}
//
//int main()
//{
//	cout << f1() << endl;
//
//	cout << f2().Top() << endl;
//	//当我们调试时会发现调试器会把st看成地址所以我们用st->_a, 3 看_a里面的东西
//	return 0;
//}

这里主要讲

// cout << f2().Top() << endl;

这个其实是先调用f2函数再调用f2.top()这个函数

还有就是我们调试想看到st这个栈中的具体值我们不能

st._a,3 因为VS编译器把它看成了地址(这是编译器的问题)所以我们要st->_a,3才能看到具体栈中的值

运算符重载

运算符重载必须要调用类函数(运算符重载是一种函数)

作用是将类对象进行加减乘除比大小(没用运算符重载对象与普通变量加减乘除比大小会报错)

c 复制代码
//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;
//		_year = year;
//		_month = month;
//		_day = day;
//	}
////private:
//	int _year;
//	int _month;
//	int _day;
//};
//
////1.提供Getxxx函数
////2.友元
////3.直接放到类里面
//
//bool operator==(const Date& x1, const Date& x2)
//{
//	cout << "我TM来了";
//		return x1._year == x2._year
//		&& x1._month == x2._month
//		&& x1._day == x2._day; 
//}
////运算符重载是特殊函数,当使用该运算符,且运算符两边类型匹配形参类型时
////编译器就会自动调用这个重载函数
////这里我们的形参是两个类类型
//int main()
//{
//	int i = 1, j = 2;
//	//bool ret1 = i < j;
//	cout << (i < j) << endl;
//
//	i++;
//
//	const Date d1(2025, 4, 25);
//	const Date d2(2025, 4, 26);
//	//bool ret2 = d1 == d2;
//	//cout << (d1 == d2) << endl;
//	//operator==(d1, d2);
//
//	Date d3(2025, 4, 25);
//	Date d4(2025, 3, 26);
//
//	cout << (d3 == d4) << endl;
//
//	return 0;
//}

运算符重载函数

可以写在全局也可以写在类函数里

结构

返回类型 operator(行参,...)

{

}

这里是写在全局

c 复制代码
//bool operator==(const Date& x1, const Date& x2)
//{
//	cout << "我TM来了";
//		return x1._year == x2._year
//		&& x1._month == x2._month
//		&& x1._day == x2._day; 
//}
c 复制代码
//cout << (d1 == d2) << endl;
//	//operator==(d1, d2);

主要讲第一个

cout << (d1 == d2) << endl;

我们看到运算符重载函数的operator后接的是 == 而且参数有两两个同类型的类

我们看到d1和d2以及中间的就会自动调用运算符重载函数 这里的作用不是比较两边对象是否相等而是调用运算符重载

运算符重载函数与拷贝构造函数调用 讲解

看到这里我们也可以写operator=

调用时我们看得到d1 = d2这里也是调用运算符重载

和拷贝构造函数的调用有点相似

Date d1 = d2;

其实是有区别的

运算符重载的这种调用d1与d2都是实例化完成的

而拷贝构造的d1还没实例化

所以这种情况调用的是实例化还是拷贝构造还是分得清的

所以目前C++的=

我们目前已知功能为赋值(两边都是普通变量)

拷贝构造

运算符重载(两种写法左边都是类类型)

这两种都是左对象为类的(都与类有关)


c 复制代码
//class Date
//{
//public:
// 
//	Date(int year, int month, int day)
//	{
//		cout << "Date(int year, int month, int day)" << endl;
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	bool operator==(const Date& d)
//	{
//		return _year == d._year
//			&& _month == d._month
//			&& _day == d._day;
//	}
//	//这里的运算符重载与之前的运算符重载函数没啥区别
//	//就是只有调用这个对象才能使用运算符重载
//
//
//	//日期减日期(相差天数)有意义
//	//int作为返回值我们称日期
//	//作为形参我们称整数在这里
//	int operator-(const Date& d);
//
//	//这里的类会隐式类型转换成int
//	//Date d1(2025,4,23)
//	//转化为int d1 2025423
//
//	//语法上可以
//	//日期加日期实践上没意义
//
//	//int operator+(const Date& d);
//
//	//日期加整数有意义
//	//Date operator+(int day);
//private:
//	int _year;
//	int _month;
//	int _day;
//};
// 类只有写拷贝构造才能与其它类或同类加减乘除比大小
////运算符重载和sizeof不要头文件
////int operator+(int x, int y);
//
//这个报错的原因是运算符重载函数有两个形参时必须要有一个自定义形参(类 / 枚举)
// 如果运算符重载只有一个形参时(运算符重载函数在类里面)形参随便 但是调用运算符重载的函数必须是类
//
//class A
//{
//public:
//	void func()
//	{
//		cout << "A::func()";
//	}
//};
//
//
//void f()
//{
//	cout << "f()" << endl;
//}
//
//
//int main()
//{
//	//函数指针
//	//普通函数指针
//	void(*func1)() = f;
//	//在c语言和c++中只有普通全局函数名就会把函数名隐式转换为函数指针(*void)
//	// 看此题它的返回内型还是不变的
//	// void(*func1)() = f;
//	// void(*func1)() = (*f)(void类型);
//	//这里讲一下加括号与不加括号的区别
//	//void(*func1)() = f;//这个是返回void的函数指针
//	//void*func1() = f;//这个是返回void*指针的函数
//	//(*func1)//说明它是函数指针
//	//这里 = f意思是将f函数的功能给予(*func1)函数指针
//	//这里
//	(*func1)();
//	//这里也不用看解引用就把它看成要使用的函数即可(其实就是函数指针解引用调用后的函数)
//	//调用直接函数名加()即可
//
//	//类的成员函数指针
//	//类的成员函数名无法隐式转换为函数指针要在函数名加&类名::(这个指的就是类函数的函数指针)
//	void(A:: * func2)() = &A::func;
//	A aa;
//	//这里的函数指针要在对象里用才行
//	//成员函数调用
//	(aa.*func2)();
//	//这里我们会有疑问void(*func1)() = f;
//	//void(A::*func2)() = &A::func;
//	//这里的*是指针还是解引用
//	//还有就是在C++中&什么时候是引用什么时候是
//	//这里我说一下在类型一边的*是指针&是引用不管有没有括号
//	// 不在类型边的*是解引用&是取地址符号
//	//
//	//
//
//	//Date d3(2025, 4, 25);
//	//为啥不能调用(访问)因为类中的函数没加public
//	//默认就是private中的没访问限定public类中定义的函数在类外都用不了
//
//
//	Date d3(2025, 4, 25);
//	Date d4(2025, 4, 26);
//
//	cout << (d3 == d4) << endl;
//	cout << d3.operator==(d4) << endl;
//	return 0;
//}

这个地方要讲解的地方较多,关于Date的运算符重载应用本章就不讲解了

c 复制代码
//class Date
//{
//public:
// 
//	Date(int year, int month, int day)
//	{
//		cout << "Date(int year, int month, int day)" << endl;
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	bool operator==(const Date& d)
//	{
//		return _year == d._year
//			&& _month == d._month
//			&& _day == d._day;
//	}
//	//这里的运算符重载与之前的运算符重载函数没啥区别
//	//就是只有调用这个对象才能使用运算符重载
//
//
//	//日期减日期(相差天数)有意义
//	//int作为返回值我们称日期
//	//作为形参我们称整数在这里
//	int operator-(const Date& d);
//
//	//这里的类会隐式类型转换成int
//	//Date d1(2025,4,23)
//	//转化为int d1 2025423
//
//	//语法上可以
//	//日期加日期实践上没意义
//
//	//int operator+(const Date& d);
//
//	//日期加整数有意义
//	//Date operator+(int day);
//private:
//	int _year;
//	int _month;
//	int _day;
//};

```c

bool operator==(const Date& d)
//	{
//		return _year == d._year
//			&& _month == d._month
//			&& _day == d._day;
//	}

这里就是运算符重载函数定义在类中

调用方式

d1.operator==(d2);

d1(类型里有这个运算符函数重载) == d2

//Date d1(2025,4,23)

由于该类变量都是int类型

//Date d1(2025,4,23)

可以隐式转换为

d1 = 2025423;

一些运算符重载有意义有些没意义

这种有关日期的int类型在形参中就称为整数

其余地方int、Date类型我们称为日期

// int operator-(const Date& d);

日期减日期为天数差有意义

// //int operator+(const Date& d);

日期加日期没意义

// //Date operator+(int day);

日期加整数有意义

////int operator+(int x, int y);

这里全局运算符重载函数参数没类类型不符合运算符重载报错


文章到此就告一段落,希望对你有所帮助,感谢观看!

相关推荐
汉克老师1 小时前
GESP2026年9月认证C++六级( 第三部分编程题(2、分树规划))精讲
c++·gesp·小学生·学c++编程
学生小羊1 小时前
C++ 初阶 学习博客
c语言·c++·c++与c语言的区别·c++基础学习
辛苦才能2 小时前
C++多态原理:虚函数表的内存布局与动态绑定的汇编真相
开发语言·c++
铲灰2 小时前
做个总结而已
开发语言
西西弗Sisyphus2 小时前
Qt 实现一个 水波进度球
c++·qt·c
无忧.芙桃2 小时前
数据结构之排序算法(中):冒泡排序与快速排序,从相邻交换到工程级优化
c语言·c++·排序算法
IvanCodes2 小时前
Python 文件操作(十二):文件与目录的读写
开发语言·python
Hhy_11072 小时前
《C++深度解构04》类和对象(下)——类型转换、static、友元与编译器优化
c语言·c++·学习·类和对象·visual studio
qq_199886873 小时前
第7板块·第1节:通用算子分类与设计模式
c++·人工智能·gpu算力·cuda