C++学习第五天

创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。


提示:以下是本篇文章正文内容,下面案例可供参考


一、构造函数

问题1

关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会
生成默认的构造函数。但是看起来默认构造函数又没什么用? d 对象调用了编译器生成的默认构造函数,但是d 对象 _year/_month/_day ,依旧是随机值。也就说在这里 编译器生成的 默认构造函数并没有什么用??
解答:C++ 把类型分成内置类型 ( 基本类型 ) 和自定义类型。内置类型就是语言提供的数据类
型,如: int/char... ,自定义类型就是我们使用 class/struct/union 等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t 调用的它的默认构造函数。


示例1:

cpp 复制代码
#include<iostream>
using namespace std;

class A
{
public:
	A(int a)
	{
		cout << "Aint(a)" << endl;
		_a = a;
	}
private:
	int _a;
};

class Date
{
public:
	//Date(int year, int month, int day)
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}
private:
	//内置类型
	int _year;
	int _month;
	int _day;

	//自定义类型
	A _aa;
};

int main()
{
	Date d1;
}

class A没有提供默认构造函数(不用参数就可以调用的构造).


示例2:

cpp 复制代码
#include<iostream>
using namespace std;

class A
{
public:
	A(int a = 0)
	{
		cout << "A int(a)" << endl;
		_a = a;
	}
private:
	int _a;
};

class Date
{
public:
	//Date(int year, int month, int day)
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}
private:
	//内置类型
	int _year;
	int _month;
	int _day;

	//自定义类型
	A _aa;
};

int main()
{
	Date d1;
}

如果A不提供默认构造,需要使用初始化列表才能解决。当前的学习暂时先通过提供全缺省( A(int a = 0) )来解决这个问题.


简单来说:我们不写编译器生成的默认构造函数,对内置类型不做处理,对自定义类型会调用它的默认构造.


二、默认构造函数

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。 注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

特点:不传参就可以调用的构造就是默认构造.


三、析构函数

可以简单理解为与构造函数相反的函数,类比Destroy函数.


日期类不需要写析构函数,因为日期类没有资源需要清理,年、月、日属于对象,不需要清理。而像栈这种才需要清理,有指向资源才需要清理。


示例1:

内置类型的成员,不做处理,造成堆上的空间没有释放,造成内存泄漏。

cpp 复制代码
#include<iostream>
using namespace std;

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	/*~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}*/
private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;

};

void TestStack()
{
	Stack s;
	s.Push(1);
	s.Push(2);
}

int main()
{
	TestStack();

	return 0;
}

示例2:

自定义类型的成员,会去调用他的析构。

cpp 复制代码
#include<iostream>
using namespace std;

class A
{
public:
	A(int a = 0)
	{
		cout << "A(int a)" << endl;
		_a = a;
	}

	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	/*~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}*/
private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;

	// 自定义类型
	A _aa;
};

void TestStack()
{
	Stack s;
	s.Push(1);
	s.Push(2);
}

int main()
{
	TestStack();

	return 0;
}

四、拷贝构造

日期类拷贝:

cpp 复制代码
#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}
private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;
};

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << "/" << endl;
	}
private:
	//内置类型
	int _year;
	int _month;
	int _day;
};

void func1(Date d)
{
	d.Print();
}

int main()
{
	Date d1(2025,1,8);
	func1(d1);

	return 0;
}

栈拷贝:

cpp 复制代码
#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}
private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;
};

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << "/" << endl;
	}
private:
	//内置类型
	int _year;
	int _month;
	int _day;
};

void func1(Date d)
{
	d.Print();
}

void func2(Stack s)
{
	
}

int main()
{
	Date d1(2025,1,8);
	func1(d1);

	Stack s1;
	func2(s1);

	return 0;
}

解决方法:

cpp 复制代码
void func2(Stack& s)
{
	//使用引用
}

拷贝构造函数

定义:只有单个形参,该形参是对本类类型对象的引用****(一般常用const修饰),在用已存
在的类类型对象创建新对象时由编译器自动调用
自定义类型传值传参要调用拷贝构造。


特征1:

拷贝构造函数是构造函数的一个重载形式


特征2:

拷贝构造函数的参数只有一个必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year, int month, int day)
	{
		cout << "Date(Date& d)" << endl;
		_year = year;
		_month = month;
		_day = day;
	}

	Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << "/" << endl;
	}
private:
	//内置类型
	int _year;
	int _month;
	int _day;
};


int main()
{
	Date d1(2025,1,8);
	Date d2(d1);

	return 0;
}
cpp 复制代码
	Date(Date d)
	{
        //没有引用会引发无穷递归调用
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

cpp 复制代码
#include<iostream>
using namespace std;

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	Stack(Stack& s)
	{
		cout << "Stack(Stack& s)" << endl;
		// 深拷贝
		_array = (DataType*)malloc(sizeof(DataType) * s._capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		
		memcpy(_array, s._array, sizeof(DataType) * s._size);
		_size = s._size;
		_capacity = s._capacity;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}
private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;
};

void func2(Stack s)
{
	s.Push(1);
}

int main()
{
	Stack s1;
	func2(s1);

	Stack s2(s1);

	return 0;
}

问题:

如果不写拷贝构造函数,系统会自动生成吗?

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}


	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		cout << "Stack()" << endl;

		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;

		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

int main()
{
	Date d1(2025, 1, 1);
	Date d2 = d1;
    
	Stack st1;
	Stack st2(st1);

	return 0;
}

特征3:

**若未显式定义,编译器会生成默认的拷贝构造函数。**默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。


复制代码
我们不写,编译默认生成的拷贝构造,跟之前的构造函数特性不一样

1、内置类型, 值拷贝

2、自定义的类型,调用他的拷贝

总结:Date不需要我们实现拷贝构造,默认生成就可以用

Stack需要我们自己实现深拷贝的拷贝构造,默认生成会出问题


MyQueue对于默认生成的几个函数非常受用,人生赢家

cpp 复制代码
#include<iostream>
using namespace std;

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		cout << "Stack()" << endl;

		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	Stack(const Stack& s)
	{
		cout << "Stack(Stack& s)" << endl;
		// 深拷贝
		_array = (DataType*)malloc(sizeof(DataType) * s._capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		memcpy(_array, s._array, sizeof(DataType) * s._size);
		_size = s._size;
		_capacity = s._capacity;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;

		free(_array);
		_array = nullptr;
		_size = _capacity = 0;
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

class MyQueue
{
private:
	Stack _pushst;
	Stack _popst;
};

int main()
{
    MyQueue mq1;
	MyQueue mq2 = mq1;

	return 0;
}

注意:

cpp 复制代码
	Date(const Date& d)
	{
      //一般情况都加上const
	  cout << "Date(Date& d)" << endl;
	  _year = d._year;
	  _month = d._month;
	  _day = d._day;
	}

 
	Date(const Date& d)
	{
	  cout << "Date(Date& d)" << endl;

      //若不小心写反了,很容易忽视这里的错误
	  d._year = _year ;
	  d._month = _month;
	  d._day = _day;
	}

五、运算符重载

问题1:

日期对象如何比较大小?能否用 < .

简单的代码实现:

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

bool DateLess (const Date& x1,const Date& x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	Date d1(2025, 1, 1);
	Date d2(2025, 1, 11);

	cout<<DateLess(d1, d2)<<endl;

	return 0;
}

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

bool operator<(const Date& x1, const Date& x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	Date d1(2025, 1, 1);
	Date d2(2025, 1, 11);

    cout << (d1 < d2) << endl;
	cout << (operator<(d1, d2)) << endl;

	return 0;
}

写为成员函数:

cpp 复制代码
// d1 < d2  
// d1.operator<(d2)
//操作数顺序不能随便换
bool operator<(const Date& d)
	{
		if (_year < d._year)
		{
			return true;
		}
		else if (_year == d._year && _month < d._month)
		{
			return true;
		}
		else if (_year == d._year && _month == d._month && _day < d._day)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

运算符复用

cpp 复制代码
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

	bool operator<(const Date& d)
	{
		if (_year < d._year)
		{
			return true;
		}
		else if (_year == d._year && _month < d._month)
		{
			return true;
		}
		else if (_year == d._year && _month == d._month && _day < d._day)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

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

	// d1 <= d2
	bool operator<=(const Date& d)
	{
		return *this < d || *this == d;
	}

	bool operator>(const Date& d)
	{
		return !(*this <= d);
	}

	bool operator>=(const Date& d)
	{
		return !(*this < d);
	}

	bool operator!=(const Date& d)
	{
		return !(*this == d);
	}
}

实现日期+运算

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

	int GetMonthDay(int year, int month)
	{
		int monthArray[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)))
		{
			return 29;
		}

		return monthArray[month];
	}

    //如果写成Date& operator+(int day)会发现Date ret = d1 + 50;中d1也会改变,所以该写成+=
	Date& operator+=(int day)
	{
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			// 月进位
			_day -= GetMonthDay(_year, _month);
			++_month;

			// 月满了
			if (_month == 13)
			{
				++_year;
				_month = 1;
			}
		}

		return *this;
	}

	Date operator+(int day)   //出了作用域对象不在了不能用引用返回
	{
		Date tmp(*this);
		tmp += day;
		return tmp;

		//tmp._day += day;
		//while (tmp._day > GetMonthDay(tmp._year, tmp._month))
		//{
		//	// 月进位
		//	tmp._day -= GetMonthDay(tmp._year, tmp._month);
		//	++_month;

		//	// 月满了
		//	if (tmp._month == 13)
		//	{
		//		++tmp._year;
		//		tmp._month = 1;
		//	}
		//}
		//return tmp;
	}

private:
	// 内置类型
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 7, 21);
	Date d2(2022, 8, 21);

	Date ret = d1 + 50;
	ret.Print();
	d1.Print();

	return 0;
}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了c++的基础知识。

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习