从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题

news2024/11/19 17:47:51

目录

1. 日期类详细实现

1.1 构造函数和打印函数

1.2 六个比较运算符重载

1.3 日期+=天数 和 日期+天数

1.4 日期 -= 天数 和 日期 - 天数

1.5 日期++ 和 ++日期

1.6 日期-- 和 --日期

1.7 日期 - 日期 operator- 

1.8  打印*this是星期几

2. 日期类完整代码

Date.h:

Date.c:

Test.c:

3. 笔试选择题

3.1 下列关于构造函数的描述正确的是( )

3.2 假定MyClass为一个类,则该类的拷贝构造函数的声明语句是( )

3.3 在函数F中,本地变量a和b的构造函数(constructor)和析构函数(destructor)的调用顺序是: ( )

3.4 设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?( )

3.5  拷贝构造函数的特点是( )

3.6 已知表达式++a中的"++"是作为成员函数重载的运算符,则与++a等效的运算符函数调用形式为( )

3.7 在重载一个运算符为成员函数时,其参数表中没有任何参数,这说明该运算符是 ( )

3.8 哪个操作符不能被重载 ( )

3.9 若要对data类中重载的加法运算符成员函数进行声明,下列选项中正确的是( )

3.10 假设 AA 是一个类, AA* abc () const 是该类的一个成员函数的原型。若该函数返回 this 值,当用 x.abc ()调用该成员函数后, x 的值是( )

3.11 下列关于赋值运算符“=”重载的叙述中,正确的是( )

答案解析:

本篇完。下一篇:(类和对象_下篇)


1. 日期类详细实现

上一篇我们讲了6个默认成员函数和运算符重载等知识,复习链接:

从C语言到C++⑤(第二章_类和对象_中篇)(6个默认成员函数+运算符重载+const成员)_GR C的博客-CSDN博客

为了能够更好地讲解运算符重载和融合以前知识,我们将来实现 一个"日期类" ,

日期类的拷贝构造、赋值、析构我们都可以不用写,让编译器自己生成就行了。

构造是要写的,剩下的你想写什么就写什么。

1.1 构造函数和打印函数

和以前做大练习一样,规范一点,我们声明与定义分离开来。

先放个样例,然后后面就不放了,最后面会放完整代码。

Date.h:

#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() const;  // 打印函数

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

Date.cpp:

#include "Date.h"

// void Date::Print(const Date* const this)
void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

Test.cpp:

#include "date.h"

void TestDate1()
{
	Date d1;
	d1.Print();

	Date d2(2023, 5, 4);
	d2.Print();
}

int main()
{
	TestDate1();

	return 0;
}

 (记录一下五一放了五天,然后五四再放半天然后还在写博客,泪目泪目)

这里的 Print 是可以加 const 的,而构造函数这里修改了成员变量,是不能加 const 的。

上一篇我们说过,加 const 是很好的,只要不改变都建议加上 const 。

我们以前讲知识点没想过:如果我们给构造函数的日期是一个非法的日期呢?

 如果有人输入了这种日期,还是能给他打印出来,这不合理,

所以我们需要设计一个函数去判断,用户输入的日期到底合不合法。

因为每个月天数不统一,所以在写判断日期合法的算法前,

我们需要先设计一个后面也用到的可以获取一年中每个月对应天数的 GetMonthDay 函数。

如何设计呢?写12个 if else?可以是可以,就是有点搓。

用 switch case 可能还好一点。和计数排序差不多,我们这里可以写个简单的哈希来解决,

我们把每个月的天数放到一个数组里,为了方便还可以把下标为 0 的位置空出来,

这里还要考虑到我们上面提到的闰年问题,闰年二月会多一天。

如果月份为 2,我们就进行判断,如果是闰年就让获取到的 day + 1 即可。

// 会频繁调用,所以直接放在类里面定义作为inline
int GetMonthDay(int year, int month)// 获取某年某月的天数
{
	//这里的数组会频繁使用,所以加上static
	static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	int day = days[month];
	if (month == 2
		&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))//先判断是否是2月
	{
		day += 1;
	}
	return day;
}

如果传入的月份是2月,就判断是否是闰年。

这里还有一个小细节就是我们是先判断传入的月份2月的,

根据 && 的特性,碰到假,后面就不会判断了,这就是一些写代码的好习惯。

然后就可以写一个检查日期是否合法的函数了:

// 会频繁调用,所以还是直接放在类里面定义作为inline
bool CheckDate()
{
	if (_year >= 1
		&& _month > 0 && _month < 13
		&& _day > 0 && _day <= GetMonthDay(_year, _month))
	{
		return true;
	}
	else
	{
		return false;
	}
}

这里一个条件放一行也是个好习惯。然后我们的构造函数就可以这样:

// 构造会频繁调用,所以直接放在类里面(类里面的成员函数默认为内联)
Date(int year = 1, int month = 1, int day = 1)
{
	_year = year;
	_month = month;
	_day = day;

	//if (!CheckDate())
	//{
	//	Print();
	//	cout << "刚构造的日期非法" << endl;
	//}

	assert(CheckDate());
}

这里使用暴力的方法,记得#include<assert.h>,然后这里就会直接报错:

然后值得一提的是类里面的成员函数和成员变量等都是被编译器看成一个整体的,

所以不用管哪个放在哪个的上面。

1.2 六个比较运算符重载

上一篇我们在讲运算符重载的时候讲了判断日期类等于的例子,

根据逻辑:任何一个类,只需要写一个> == 或者 < ==重载 剩下的比较运算符重载复用即可

日期的判断很简单,我们只需要挨个对比就可以了,结果返回布尔值,没什么好说的。

我们这里写判断等于和判断大于然后直接放出日期类比较运算符重载的部分,

判断等于:

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

判断大于:

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

Date.h:

#pragma once

#include <iostream>
#include <assert.h>
using namespace std;

class Date
{
public:
	// 构造会频繁调用,所以直接放在类里面(类里面的成员函数默认为内联)
	Date(int year = 1, int month = 1, int day = 1)//构造
	{
		_year = year;
		_month = month;
		_day = day;
		//if (!CheckDate())
		//{
		//	Print();
		//	cout << "刚构造的日期非法" << endl;
		//}
		assert(CheckDate());
	}

	void Print() const;  // 打印

	int GetMonthDay(int year, int month)// 获取某年某月的天数
	{
		static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		int day = days[month];
		if (month == 2
			&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			day += 1;
		}
		return day;
	}

	bool CheckDate()// 检查日期是否合法
	{
		if (_year >= 1
			&& _month > 0 && _month < 13
			&& _day > 0 && _day <= GetMonthDay(_year, _month))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

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

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

Date.c:

#include "Date.h"

// void Date::Print(const Date* const this)
void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

// 任何一个类,只需要写一个> == 或者 < ==重载 剩下比较运算符重载复用即可
bool Date::operator== (const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

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

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

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

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

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

Test.c:

#include "Date.h"

void TestDate1()
{
	Date d1;
	d1.Print();

	Date d2(2023, 5, 4);
	d2.Print();

	Date d3(2026, 5, 1);
	Date d4(2020, 5, 20);

	cout << (d2 > d3) << endl;
	cout << (d2 == d3) << endl;
	cout << (d2 != d3) << endl;
	cout << (d2 >= d4) << endl;
	cout << (d2 < d4) << endl;
	cout << (d2 <= d4) << endl;
}

int main()
{
	TestDate1();

	return 0;
}

1.3 日期+=天数 和 日期+天数

日期加一个日期没什么意义,但是加天数的场景就很多了。

比如我们想让当前日期加100天:

Date d1(2023, 5, 4);
d1 += 100;
d1.Print();

Date d2(2023, 5, 4);
d3 = d2 + 100;
d2.Print();
d3.Print();

体会了上面代码复用的方便,思考一下先实现+=还是+呢?

+= 原来的值变了,+ 原来的值没有变,返回的都是+之后的值

+ 还要调用两次拷贝,所以先实现+= 好一点点

日期加天数把进位搞定就可以了,我们把天数全都加到day上,

只需要判断加完日期后天数合不合法,

看它加完后的天数有没有超出这个月的天数,如果超过了就不合法。

这个我们刚才已经实现过 GetMonthDay 了,这里就直接拿来用就行了。

如果不合法,我们就进位。天满了往月进,月再满就往年进。

因为出了作用域对象还在,我们可以使用引用返回减少拷贝:

Date& Date::operator+=(int day)//这里没考虑day是负数的情况,最后放的代码加上了
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

+= 是改变 "本体",但是 + 并不会,所以这里可以加个 const 修饰一下。

+ 和 += 很类似,也是通过 "判断" 就可以实现的,复用一下 += :

Date Date::operator+(int day) const//不改变,用const
{
	Date ret = *this; 
	ret += day;

	return ret;// 出了作用域ret对象就不在了,所以不能用引用返回
}

因为我们 + 是复用 += 的,所以我们只测试+应该就没什么问题

 上面的日期可以用网上搜的日期计算器搜索来验证:

1.4 日期 -= 天数 和 日期 - 天数

我们刚才实现了加和加等 ,现在我们来实现一下减和减等。

加和加等是进位,那减和减等自然就是借位。

我们先把day减一下天数,此时如果日期不合法,那我们就需要进行借位操作。

和上面一样我们先实现减等:

Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

如果减完后的天数小于等于 0,就进入循环,向月 "借位" ,

因为已经借出去了,所以把 月份 -- 。还要考虑月份会不会借完的情况,

月份为 0 的时候就是没得借了,这种情况就向年借,年--,

之后加上通过 GetMonthDay 获取当月对应的天数,就是所谓的 "借",

循环继续判断,直到天数大于0的时候停止,返回 *this  。

出了作用域 *this 还在,所以我们可以使用引用返回 Date& 。

一样的,我们复用一下 -= 就可以把 - 实现出来了:

Date Date::operator-(int day) const
{
	Date ret = *this;
	ret -= day;// ret.operator-=(day);

	return ret;// 和+一样,出了作用域ret对象就不在了,所以不能用引用返回
}

 到这我们发现日期计算器是可以输入负数的,那我们的输入负数呢:

我们发现,在设计 operator-= 的时候是 <= 0 才算非法的,所以这种情况就没考虑到。

我们可以这么设计,在减天数之前对 day 进行一个特判,

因为你减负的100就相当于加正的100,就变成加了,

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

我们再回去把 operator+= 处理一下:

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

1.5 日期++ 和 ++日期

d1++;
++d1;

因为都是 operator++ ,为了能让编译器直到我们实现的到底是 前置++ 还是 后置++,

这里就到用到一个叫做 "参数占位" 的东西 :int ,即:

后置++ 带  " int " ,构成函数重载。

operator++(int);     // 带int,表示后置加加   d1++
operator++();        // 不带, 表示前置加加   ++d1

根据上面的经验,我们先实现返回运算符作用后的值的前置++

因为 前置++ 返回的是加加之后的值,所以我们使用引用返回:

Date& Date::operator++() // 前置
{
	return 	*this += 1;
}

这里我们直接复用 +=,加加以后的值就是 *this ,我们返回一下 *this 就行。

因为后置++返回的是加加之前的值,所以我们不用引用返回:

Date Date::operator++(int) // 后置
{
	Date ret = *this;
	*this += 1;

	return ret;
}

这里要拷贝构造两次,所以我们推荐以后自定义类型++,使用前置++ 。

对于内置类型,用前置比后置也好那么一丢丢,但现在几乎可忽略不计,

为了和自定义类型对应好看点,我们以后对于内置类型也尽量用前置好了

1.6 日期-- 和 --日期

和 operator++ 一样,operator-- 为了能够区分前置和后置,也要用 int 参数占位

 后置-- 带  " int " ,构成函数重载。

 前置-- 返回的是减减之后的值,所以我们使用引用返回:

Date& Date::operator--() // 前置
{
	return *this -= 1;
}

后置-- 返回的是减减之前的值,所以我们不用引用返回,

我们在减减之前先拷贝构造一个 "替身" ,待本体加加后,

把替身 ret 返回回去,就实现了返回减减之前的值:

Date Date::operator--(int) // 后置
{
	Date ret = *this;
	*this -= 1;

	return ret;
}

和后置++一样这里要拷贝构造两次,所以我们推荐以后自定义类型--,使用前置-- 。

1.7 日期 - 日期 operator- 

我们刚才实现的 operator是日期减天数的:

Date Date::operator-(int day) const
{
	Date ret = *this;
	ret -= day;// ret.operator-=(day);

	return ret;// 和+一样,出了作用域ret对象就不在了,所以不能用引用返回
}

日期 + 日期 没什么意义,但是日期 - 日期还是有意义的,

如果我们想要计算一下今天距离高考还有多少天呢?

那我们就需要写一个日期减日期版本的 operater 

因为有正用负,我们利用学二叉树时讲过的思想吧

之后我们用计数器的方式来实现就可以了 :

int Date::operator-(const Date& d) const
{
	int ret = 0;
	int flag = -1;
	Date min = *this;//默认第一个小,返回的时候乘上 -1
	Date max = d;

	if (*this > d)//默认错误,把小和大重置,返回时乘上 1
	{
		flag = 1;
		min = d;
		max = *this;
	}

	while (min != max)
	{
		++min;
		++ret;
	}

	return ret * flag;
}

 

1.8  打印*this是星期几

前面我们使用日期计算器得出一个日期的时候,它都会给我们那个日期是星期几,

我们也来实现一个类似的功能。

我们需要找一个标志日期,知道那一天是星期几,然后复用上面的代码就能实现这个功能,

因为十六世纪有日期被抹掉了,所以我们拿 1900年1月1号(刚好是星期一) 作为起始点,

和上面一样创建一个const数组,

两个日期相减得到的结果,%7 作为下标去访问 Week 数组里我们已经准备好的周几,

打印出来就可以了:

void Date::PrintWeekDay() const //打印*this是星期几
{
	const char* Week[] = { "星期一","星期二" ,"星期三" , "星期四" ,"星期五" , "星期六" , "星期天" };
	Date flag(1900, 1, 1); //1900年1月1日是星期一,自己减自己为0,对应下标0

	cout << Week[(*this - flag) % 7] << endl;
}

 

2. 日期类完整代码

Date.h:

#pragma once

#include <iostream>
#include <assert.h>
using namespace std;

class Date
{
public:
	// 构造会频繁调用,所以直接放在类里面(类里面的成员函数默认为内联)
	Date(int year = 1, int month = 1, int day = 1)//构造
	{
		_year = year;
		_month = month;
		_day = day;
		//if (!CheckDate())
		//{
		//	Print();
		//	cout << "刚构造的日期非法" << endl;
		//}
		assert(CheckDate());
	}

	void Print() const;  // 打印

	int GetMonthDay(int year, int month)// 获取某年某月的天数
	{
		static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		int day = days[month];
		if (month == 2
			&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			day += 1;
		}
		return day;
	}

	bool CheckDate()// 检查日期是否合法
	{
		if (_year >= 1
			&& _month > 0 && _month < 13
			&& _day > 0 && _day <= GetMonthDay(_year, _month))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

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

	Date& operator+=(int day);
	Date operator+(int day) const;
	Date& operator-=(int day);
	Date operator-(int day) const;
	// 特殊处理,使用重载区分,后置++重载增加一个int参数跟前置构成函数重载进行区分
	Date& operator++(); // 前置
	Date operator++(int); // 后置
	Date& operator--();// 前置
	Date operator--(int);// 后置

	int operator-(const Date& d) const; //日期减日期

	void PrintWeekDay() const; //返回*this是星期几

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

Date.c:

#include "Date.h"

// void Date::Print(const Date* const this)
void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

// 任何一个类,只需要写一个> == 或者 < ==重载 剩下比较运算符重载复用即可
bool Date::operator== (const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

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

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

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

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

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

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

Date Date::operator+(int day) const
{
	Date ret = *this; 
	ret += day;

	return ret;// 出了作用域ret对象就不在了,所以不能用引用返回
}

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

Date Date::operator-(int day) const
{
	Date ret = *this;
	ret -= day;// ret.operator-=(day);

	return ret;// 和 + 一样,出了作用域ret对象就不在了,所以不能用引用返回
}

Date& Date::operator++() // 前置
{
	return 	*this += 1;
}
Date Date::operator++(int) // 后置
{
	Date ret = *this;
	*this += 1;
	return ret;
}

Date& Date::operator--() // 前置
{
	return *this -= 1;
}
Date Date::operator--(int) // 后置
{
	Date ret = *this;
	*this -= 1;

	return ret;
}

int Date::operator-(const Date& d) const
{
	int ret = 0;
	int flag = -1;
	Date min = *this;//默认第一个小,返回的时候乘上 -1
	Date max = d;

	if (*this > d)//默认错误,把小和大重置,返回时乘上 1
	{
		flag = 1;
		min = d;
		max = *this;
	}

	while (min != max)
	{
		++min;
		++ret;
	}

	return ret * flag;
}

void Date::PrintWeekDay() const //打印*this是星期几
{
	const char* Week[] = { "星期一","星期二" ,"星期三" , "星期四" ,"星期五" , "星期六" , "星期天" };
	Date flag(1900, 1, 1); //1900年1月1日是星期一,自己减自己为0,对应下标0

	cout << Week[(*this - flag) % 7] << endl;
}

Test.c:

#include "Date.h"

void TestDate1()
{
	Date d1;
	d1.Print();

	Date d2(2023, 5, 4);
	d2.Print();

	Date d3(2026, 5, 1);
	Date d4(2020, 5, 20);

	cout << (d2 > d3) << endl;
	cout << (d2 == d3) << endl;
	cout << (d2 != d3) << endl;
	cout << (d2 >= d4) << endl;
	cout << (d2 < d4) << endl;
	cout << (d2 <= d4) << endl;
}

void TestDate2()
{
	Date d1(2023, 5, 4);
	Date d2 = d1 + 14;
	d2.Print();//我们还可以这样写:
	(d1 + 40).Print();// 跨月
	(d1 + 400).Print();// 跨年
	(d1 + 4000).Print(); // 跨闰年
	(d1 + 40000).Print();
}

void TestDate3()
{
	Date d1(2023, 5, 4);
	Date d2 = d1 - -4;
	d2.Print();//我们还可以这样写:
	(d1 - -40).Print();// 跨月
	(d1 - -400).Print();// 跨年
	(d1 - -4000).Print(); // 跨闰年
	(d1 - 4000).Print(); // 跨闰年
	(d1 - 40000).Print();
}

void TestDate4()
{
	Date d1(2023, 5, 4);
	Date d2 = ++d1;
	d1.Print();
	d2.Print();

	Date d3(2023, 5, 31);
	Date d4 = d3++;
	d3.Print();
	d4.Print();
}

void TestDate5()
{
	Date d1(2023, 5, 4);
	Date d2 = --d1;
	d1.Print();
	d2.Print();

	Date d3(2023, 5, 1);
	Date d4 = d3--;
	d3.Print();
	d4.Print();
}

void TestDate6()
{
	Date d1(2023, 5, 5);
	Date d2(2023, 6, 7);
	d1.Print();
	d2.Print();
	cout << (d1 - d2) << endl << endl;

	Date d3(2023, 5, 5);
	Date d4(2000, 1, 1);
	d3.Print();
	d4.Print();
	cout << (d3 - d4) << endl << endl;

	Date d5(2100, 1, 1);
	Date d6(2000, 1, 1);
	d5.Print();
	d6.Print();
	cout << (d5 - d6) << endl;
}

void TestDate7()
{
	Date d1(2023, 5, 5);
	Date d2(2023, 6, 7);
	d1.Print();
	d1.PrintWeekDay();
	d2.Print();
	d2.PrintWeekDay();

	Date d3(1900, 1, 7);
	Date d4(2050, 6, 7);
	d3.Print();
	d3.PrintWeekDay();
	d4.Print();
	d4.PrintWeekDay();
}

int main()
{
	//TestDate1();
	//TestDate2();
	//TestDate3();
	//TestDate4();
	//TestDate5();
	//TestDate6();
	TestDate7();

	return 0;
}

3. 笔试选择题

再贴下知识点复习链接:

从C语言到C++⑤(第二章_类和对象_中篇)(6个默认成员函数+运算符重载+const成员)_GR C的博客-CSDN博客

3.1 下列关于构造函数的描述正确的是( )

A.构造函数可以声明返回类型

B.构造函数不可以用private修饰

C.构造函数必须与类名相同

D.构造函数不能带参数

3.2 假定MyClass为一个类,则该类的拷贝构造函数的声明语句是( )

A.MyClass(MyClass x)

B.MyClass &(MyClass x)

C.MyClass(MyClass &x)

D.MyClass(MyClass *x)

3.3 在函数F中,本地变量a和b的构造函数(constructor)和析构函数(destructor)的调用顺序是: ( )

Class A;
Class B;

void F()
{
	A a;
	B b;
}

A.b构造 a构造 a析构 b析构

B.a构造 a析构 b构造 b析构

C.b构造 a构造 b析构 a析构

D.a构造 b构造 b析构 a析构

3.4 设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?( )

C c;
int main()
{
	A a;
	B b;
	static D d;

	return 0;
}

A.D B A C

B.B A D C

C.C D B A

D.A B D C

3.5  拷贝构造函数的特点是( )

A.该函数名同类名,也是一种构造函数,该函数返回自身引用

B.该函数只有一个参数,是对某个对象的引用

C.每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员

D.拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象

3.6 已知表达式++a中的"++"是作为成员函数重载的运算符,则与++a等效的运算符函数调用形式为( )

A.a.operator++()

B.a.operator++(0)

C.a.operator++(int)

D.operator++(a,0)

3.7 在重载一个运算符为成员函数时,其参数表中没有任何参数,这说明该运算符是 ( )

A.无操作数的运算符

B.二元运算符

C.前缀一元运算符

D.后缀一元运算符

3.8 哪个操作符不能被重载 ( )

A.*

B.()

C.. (点)

D.[]

E.->

3.9 若要对data类中重载的加法运算符成员函数进行声明,下列选项中正确的是( )

A.Data operator+(Data);

B.Data operator(Data);

C.operator+(Data,Data);

D.Data+(Data);

3.10 假设 AA 是一个类, AA* abc () const 是该类的一个成员函数的原型。若该函数返回 this 值,当用 x.abc ()调用该成员函数后, x 的值是( )

A.可能被改变

B.已经被改变

C. 受到函数调用的影响

D.不变

3.11 下列关于赋值运算符“=”重载的叙述中,正确的是( )

A.赋值运算符只能作为类的成员函数重载

B.默认的赋值运算符实现了“深层复制”功能

C.重载的赋值运算符函数有两个本类对象作为形参

D.如果己经定义了复制拷贝构造函数,就不能重载赋值运算符

答案解析:

3.1 C

A.构造函数不能有返回值,包括void类型也不行

B.构造函数可以是私有的,只是这样之后就不能直接实例化对象

C.这是必须的

D.构造函数不光可以带参数,还可以有多个构造函数构成重载

3.2 C

A.参数必须是引用,否则造成无限递归

B.语法错误

C.正确

D.这种写法只是普通的构造函数,不能成为拷贝构造函数

3.3 D

A.构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构,因此先构造b错误

B.a析构的时机不对,对象析构要在生存作用域结束的时候才进行析构,因此先析构a错误

C.b的构造时机错误,先构造a

D.正确,构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构

3.4 B

分析:1、类的析构函数调用一般按照构造函数调用的相反顺序进行调用,但是要注意static对象的存在, 因为static改变了对象的生存作用域,需要等待程序结束时才会析构释放对象

   2、全局对象先于局部对象进行构造

   3、局部对象按照出现的顺序进行构造,无论是否为static

   4、所以构造的顺序为 c a b d

   5、析构的顺序按照构造的相反顺序析构,只需注意static改变对象的生存作用域之后,会放在局部 对象之后进行析构

   6、因此析构顺序为B A D C

3.5 D

A.拷贝构造函数也是一构造函数,因此不能有返回值

B.该函数参数是自身类型的对象的引用

C.自动生成的缺省拷贝构造函数,作为该类的公有成员,否则无法进行默认的拷贝构造

D.用对象初始化对象这是拷贝构造函数的使命,故正确

3.6 A

A.正确

B.operator++()传递了整形参数,故为后置++,错误

C.调用函数传递类型,导致语法错误

D.参数过多,语法错误

3.7 C

A.重载为成员函数时,其函数的参数个数与真实的函数参数个数会减少1个,减少的则 通过this指针进行传递,所以无参  则说明有一个参数,故错误

B.无参成员函数相当于有一个参数的全局函数,不能是二元运算符

C.正确

D.区分前缀后缀时,后缀运算需要加一个int参数

3.8 C

A.可以,例如重载对象取值,典型有以后学到的智能指针

B.可以,例如以后学到的仿函数就是通过重载()实现的

C.不能,不能被重载的运算符只有5个, 点号. 三目运算?: 作用域访 问符:: 运算符sizeof 以及.*

D.可以,例如重载对象的指向,典型有以后学到的智能指针

3.9 A

A.正确

B.语法错误,缺少运算符+

C.成员函数参数过多

D.没有运算符重载关键字operator

3.10 D

A.此成员函数被定义为const常方法,代表在函数内部不能修改任何当前对象的数据成员,因此x不可能改变

B.错误,不能被改变

C.x的值在函数内部不受任何影响

D.正确

3.11 A

A. 赋值运算符在类中不显式实现时,编译器会生成一份默认的,此时用户在类外再将赋值运算符重载为全局的,就和编译器生成的默认赋值运算符冲突了,故赋值运算符只能重载成成员函数

B.默认的赋值运算符是按成员成员,属于浅赋值

C.参数只有一个,另一个通过this指针传递

D.两个函数的调用场景不同,相互没有影响

本篇完。下一篇:(类和对象_下篇)

现在没能体会到C++的方便,学完类和对象学一点STL库就能体会到了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492119.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机智能系统有哪些SCI期刊? - 易智编译EaseEditing

计算机智能系统是计算机科学中的一个重要分支&#xff0c;其主要研究计算机智能和人工智能等方面的问题。以下是一些SCI期刊的推荐&#xff1a; IEEE Transactions on Neural Networks and Learning Systems&#xff1a; 该期刊是IEEE计算智能学会的官方期刊&#xff0c;涵盖了…

JavaWeb——数据链路层详解

目录 一、以太网 1、定义 2、以太网格式帧 二、MTU 1、定义 2、MTU对IP协议的影响 3、MTU对UDP协议的影响 4、MTU对TCP协议的影响 三、ARP协议 1、定义 2、ARP协议的作用 3、ARP协议的工作流程 一、以太网 1、定义 "以太网" 不是一种具体的网络&#xff…

谷歌浏览器 | Chrome DevTools系统学习篇-概述

Chrome DevTools是一套直接内置到谷歌Chrome浏览器的web开发工具。DevTools可以帮助您即时编辑页面并快速诊断问题&#xff0c;最终帮助您更快地构建更好的网站。我们今天的概述主要讲述谷歌浏览器的日常使用和几大常见控制面板的介绍。 目录 1.打开谷歌浏览器 2.谷歌浏览器的…

MySQL 页、页结构、页目录、索引

MySQL中&#xff0c;数据存到了什么地方&#xff1f; 存储到了硬盘的文件上&#xff0c;被称为&#xff1a;数据文件 或 表空间 每个数据库都是由 一组数据文件 组成&#xff0c;这些文件包含了&#xff1a;所有表、索引、其他相关对象的数据 MySQL 以什么样的方式访问&#…

安卓联发科MT6737手机开发核心板 开发模块

MT6737核心板是一款基于联发科MT6737T平台高性能、可运行安卓操作系统的4G智能模块。它支持多种制式&#xff0c;包括LTE-FDD/LTE-TDD/WCDMA/TD-SCDMA/EVDO/CDMA/GSM等。此外&#xff0c;它还支持WiFi 802.11a/b/g/n和BT4.0LE近距离无线通信&#xff0c;并支持GPS/GLONASS/北斗…

机器学习笔记之计算学习理论(二)PAC学习

机器学习笔记之计算学习理论——PAC学习 引言回顾&#xff1a;霍夫丁不等式霍夫丁不等式的问题及其优化 PAC \text{PAC} PAC引出新问题——霍夫丁不等式无法通过直接比较获取最优假设函数问题的解决方法新方法对于霍夫丁不等式的约束证明 总结 引言 上一节从霍夫丁不等式为切入…

STC32G12K128单片机的 moubus-rtu 从机测试工程

简介 STC32G12K128 是STC 推出的一款32位的 C251 的单片机。最近拿到一块官方申请的 屠龙刀-STC32G开发板&#xff0c;就用它的提供的库函数&#xff0c;查考安富莱提供的 modbus 例程移植了一个 modbus-rtu 从站的工程。 modbus-rtu slave 移植注意点 modbus-rtu 功能配置 …

每日学术速递5.3

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Learning Locally Editable Virtual Humans 标题&#xff1a;学习本地可编辑虚拟人 作者&#xff1a;Hsuan-I Ho, Lixin Xue, Jie Song, Otmar Hilliges 文章链接&#xff1a;htt…

【分享】7-Zip解压缩软件的超详细使用攻略

常用的解压缩软件&#xff0c;除了WinRAR之外&#xff0c;7-Zip也是不错的选择。 7-Zip不仅是一款完全免费的开源解压软件&#xff0c;它的解压缩功能也很强大&#xff0c;可以支持视频、文档、文件夹、图片等文件进行压缩操作。 今天小编就来分享一下&#xff0c;7-Zip解压缩…

python一键登录srun校园网(以深圳技术大学为例)

全世界最&#xff08;不&#xff09;好的目录 一、需求分析二、实现过程2.1 分析api2.1.1 连接到校园网&#xff0c;自动弹出登录认证界面2.1.2 先输入错误的账号密码&#xff0c;按F12看会获取哪些信息2.1.3 api 2.2 分析加密2.3 流程总结 三.模拟登录3.1 编写配置文件3.2.功能…

【微软Bing王炸更新】无需等待,人人可用,答案图文并茂,太牛了

&#x1f680; AI破局先行者 &#x1f680; &#x1f332; AI工具、AI绘图、AI专栏 &#x1f340; &#x1f332; 如果你想学到最前沿、最火爆的技术&#xff0c;赶快加入吧✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域优质创作者&#x1f3c6;&am…

opencv实践项目-图像拼接

目录 1.简介2. 步骤2.1 特征检测与提取2.2 关键点检测2.3 关键点和描述符2.4 特征匹配2.5 比率测试2.6 估计单应性 3. 完整代码 1.简介 图像拼接是计算机视觉中最成功的应用之一。如今&#xff0c;很难找到不包含此功能的手机或图像处理API。在本 文中&#xff0c;我们将讨论如…

虹科分享 | 专为创意专业人士设计的Thunderbolt适配器

一、方案介绍 虹科HK-ATTO ThunderLink雷电™ 适配器可以适用于任何地方。 1.小。 2.便携式。 3.强大。 我们的10GBE Thunderbolt适配器的性能至少比内置或附加NIC&#xff08;包括Mac&#xff09;高20% , ATTO 360只需点击一个按钮即可优化以太网SAN&#xff0c;并可与Thunder…

xxl-job 使用示例

目录 介绍 下载源码地址 文档网站 源码导入就是这样目录 数据库建表sql 就这么几个表出来了 修改xxl-job-admin项目下的application.properties文件 完事启动就行了 页面 页面访问地址 账号密码 增加自己的定时任务 介绍 这篇写的是接入使用xxl-job 的一个简单流程…

win系统使用macOS系统

最近 win 系统和 ubuntu 系统用的久了&#xff0c;想用一下 MacOS 系统&#xff0c;于是去网上查了相关资料&#xff0c;发现用一款叫 NEXUS 的软件可以实现在 windows 系统体验效果&#xff0c;现把教程记录下来&#xff0c;供大家使用。 目录 一、下载NEXUS 二、 安装NEXU…

IMX6ULL裸机篇之串口实验说明一

一. 串口 本章我们就来学习如何驱动 I.MX6U 上的串口&#xff0c;并使用串口和电脑进行通信。 串行接口指的是数据一个一个的顺序传输&#xff0c;通信线路简单。 UART 作为串口的一种&#xff0c;其工作原理也是将数据一位一位的进行传输&#xff0c;发送和接收各用一 条…

win11本地安全机构保护已关闭怎么办?如何修复windows11本地安全机构保护已关闭?

win11本地安全机构保护已关闭怎么办&#xff1f; 如何修复windows11本地安全机构保护已关闭&#xff1f; 近日有windows11系统用户反映说遇到了这样一个问题&#xff1a;启动电脑后&#xff0c;发现windows右下角的安全中心图标上会显示一个黄色叹号&#xff0c;打开windows安…

操作系统笔记--进程与线程

1--进程 1-1--进程的定义 进程表示一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程&#xff1b; 1-2--进程的组成 一个进程由以下部分组成&#xff1a;① 程序的代码&#xff1b; ② 程序处理的数据&#xff1b;③ 程序计数器中的值&#xff0c;其指示下一条将…

PHP流行框架的报错页面,你见过那些?

在PHP开发过程中&#xff0c;使用框架能够帮助我们更快速、高效地完成项目开发。但是&#xff0c;即使使用了框架&#xff0c;我们还是难免会遇到各种报错。而当我们在开发阶段或调试过程中遇到报错时&#xff0c;框架提供的错误页面可以给我们带来很大的帮助。PHP常用的流行框…

网易一面:如何设计线程池?请手写一个简单线程池?

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如极兔、有赞、希音、百度、网易的面试资格&#xff0c;遇到了几个很重要的面试题&#xff1a; 如何设计线程池&#xff1f; 与之类似的、其他小伙伴遇到过的问题还有&#xff1a; …