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

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

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;
}

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.两个函数的调用场景不同,相互没有影响

本篇完。



510d299afd0b4f95989cd8066a224387.png


目录
相关文章
|
存储 编译器 C语言
C语言存储类详解
在 C 语言中,存储类定义了变量的生命周期、作用域和可见性。主要包括:`auto`(默认存储类,块级作用域),`register`(建议存储在寄存器中,作用域同 `auto`,不可取地址),`static`(生命周期贯穿整个程序,局部静态变量在函数间保持值,全局静态变量限于本文件),`extern`(声明变量在其他文件中定义,允许跨文件访问)。此外,`typedef` 用于定义新数据类型名称,提升代码可读性。 示例代码展示了不同存储类变量的使用方式,通过两次调用 `function()` 函数,观察静态变量 `b` 的变化。合理选择存储类可以优化程序性能和内存使用。
535 83
|
存储 C++
【C++篇】C++类和对象实践篇——从零带你实现日期类的超详细指南
【C++篇】C++类和对象实践篇——从零带你实现日期类的超详细指南
394 2
【C++篇】C++类和对象实践篇——从零带你实现日期类的超详细指南
|
编译器 C语言 C++
【C语言程序设计——选择结构程序设计】求输入的日期是该年的第几天(头歌实践教学平台习题)【合集】
本任务要求编写程序,根据用户输入的年月日(以空格或回车分隔),计算并输出该天是该年的第几天,需注意判断闰年。主要内容包括: 1. **任务描述**:实现从键盘输入年月日,计算该天是当年的第几天。 2. **相关知识**: - `switch` 结构的基本语法及使用注意事项。 - 判断闰年的条件:能被4整除但不能被100整除,或能被400整除的年份为闰年。 3. **编程要求**:根据提示补充代码,确保程序正确处理输入并输出结果。 4. **测试说 示例代码展示了如何使用 `switch` 语句和闰年判断逻辑来完成任务。通过此练习,掌握 `switch` 语句的应用及闰年判断方法。
677 0
|
C语言 C++
C 语言的关键字 static 和 C++ 的关键字 static 有什么区别
在C语言中,`static`关键字主要用于变量声明,使得该变量的作用域被限制在其被声明的函数内部,且在整个程序运行期间保留其值。而在C++中,除了继承了C的特性外,`static`还可以用于类成员,使该成员被所有类实例共享,同时在类外进行初始化。这使得C++中的`static`具有更广泛的应用场景,不仅限于控制变量的作用域和生存期。
516 10
【C++】实现日期类相关接口(三)
【C++】实现日期类相关接口
181 5
|
C++
C++番外篇——日期类的实现
C++番外篇——日期类的实现
539 1
【C++】实现日期类相关接口(二)
【C++】实现日期类相关接口
226 1
【C++】实现日期类相关接口(一)
【C++】实现日期类相关接口
185 1
|
算法 编译器 C语言
【C语言】C++ 和 C 的优缺点是什么?
C 和 C++ 是两种强大的编程语言,各有其优缺点。C 语言以其高效性、底层控制和简洁性广泛应用于系统编程和嵌入式系统。C++ 在 C 语言的基础上引入了面向对象编程、模板编程和丰富的标准库,使其适合开发大型、复杂的软件系统。 在选择使用 C 还是 C++ 时,开发者需要根据项目的需求、语言的特性以及团队的技术栈来做出决策。无论是 C 语言还是 C++,了解其优缺点和适用场景能够帮助开发者在实际开发中做出更明智的选择,从而更好地应对挑战,实现项目目标。
704 0
|
存储 缓存 程序员
c语言的存储类型-存储类
本文详细介绍了C语言中的存储类型及其分类,包括基本类型(如整型、浮点型)和复合类型(如数组、结构体)。重点讲解了不同存储类别(`auto`、`static`、`register`、`extern`、`typedef`、`volatile`、`const`)的特点及应用场景,并展示了C11/C99引入的新关键字(如`_Alignas`、`_Atomic`等)。通过示例代码解释了每个存储类别的具体用法,帮助读者更好地理解和运用这些概念。