[c++]类和对象常见题目详解

简介: [c++]类和对象常见题目详解


1.求1+2+3+…+n

题目来源:求1+2+3+…+n

题目描述:

 求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

示例:

 输入:5

 返回值:15

分析:

 若是只看题目不管要求,这是一道非常简单的题目,我们有好几种方式可以得出最终结果,但加上题目限制条件,可能大多数博友都懵了。

我们来捋一捋:

 1、不能使用乘除法,等差数列求和公式不能用了。

 2、不能使用for、while,循环求解不能用了。

 3、不能使用switch、case和A?B:C,递归求解也不能用了。

思路:

这道题用常规的方式确实解决不了,因为题目把我们要用到的东西都限制死了。解决这道题之前我们需要知道:当一个对象被创建的时候,该对象会自动调用其默认构造函数。

 我们需要计算的是1-n这n个数的和,那么我们可以创建n个类对象,这样就可以调用n次构造函数,这就相当于代替了递归。每次需要被加的数都比上一次被加的数大一,我们可以借助于类的静态成员变量,在构造函数中设置该静态成员变量自增即可实现。特别注意,这里必须是静态成员变量,不能是普通的成员变量,因为每个对象被创建时都有属于自己的普通成员变量,而静态成员变量是属于整个类的,这样才能使得这n次调用构造函数时自增的是同一个变量,每个对象访问到的静态成员变量是同一个。同理,存储累加结果的变量也必须是静态成员变量。

class Add
{
public:
  Add() //构造函数
  {
    _num++;
    _ret += _num;
  }
  static int _num; //静态成员变量,存储正在累加的数字
  static int _ret; //静态成员变量,存储1+2+3+...+n的结果
};
//静态成员变量的定义
int Add::_num = 0;
int Add::_ret = 0;
class Solution 
{
public:
  int Sum_Solution(int n) 
  {
    //多个测试用例,可能会多次调用,做好初始化工作
    //防止第二个测试用例的结果是在第一个测试用例的基础上继续累加得到的
    Add::_num = 0;
    Add::_ret = 0;
    Add* p = new Add[n]; //为n个Add类对象申请空间(可调用n次构造函数)
    return Add::_ret; //返回1+2+3+...+n的结果
  }
};

代码中为了可以通过类名和类的访问限定符直接突破类域,进而访问到静态成员变量,于是把类的成员变量直接设置为了公有(public)。我们知道,将类的成员变量设置为公有是不安全的,对此,我们可以使用友元类来解决该问题。

class Add
{
  friend class Solution; //声明Solution是Add的有元类
public:
  Add() //构造函数
  {
    _num++;
    _ret += _num;
  }
private:
  static int _num; //静态成员变量,存储正在累加的数字
  static int _ret; //静态成员变量,存储1+2+3+...+n的结果
};
//静态成员变量的定义
int Add::_num = 0;
int Add::_ret = 0;
class Solution {
public:
  int Sum_Solution(int n) {
    //多个测试用例,可能会多次调用,做好初始化工作
    //防止第二个测试用例的结果是在第一个测试用例的基础上继续累加得到的
    Add::_num = 0;
    Add::_ret = 0;
    Add* p = new Add[n]; //为n个Add类对象申请空间(可调用n次构造函数)
    return Add::_ret; //返回1+2+3+...+n的结果
  }
};

代码中我们将Solution声明为Add的友元类,这样Solution类的成员函数就可以访问Add中的非公有成员了。但在某种意义上来说,使用友元是破坏了封装的,使得Solution类的独立性降低了。

 实际上,访问类中的静态成员变量最标准的方法是通过静态成员函数,我们可以通过定义静态成员函数来获取静态成员变量,或是对静态成员变量进行修改。

class Add
{
public:
  Add() //构造函数
  {
    _num++;
    _ret += _num;
  }
  static void Init() //对静态成员变量进行初始化
  {
    _num = 0;
    _ret = 0;
  }
  static int Getret() //获取静态成员变量_ret
  {
    return _ret;
  }
private:
  static int _num; //静态成员变量,存储正在累加的数字
  static int _ret; //静态成员变量,存储1+2+3+...+n的结果
};
//静态成员变量的定义
int Add::_num = 0;
int Add::_ret = 0;
class Solution 
{
public:
  int Sum_Solution(int n) 
  {
    //多个测试用例,可能会多次调用,做好初始化工作
    //防止第二个测试用例的结果是在第一个测试用例的基础上继续累加得到的
    Add::Init();
    //Add arr[n];
    Add* p = new Add[n]; //为n个Add类对象申请空间(可调用n次构造函数)
    return Add::Getret(); //返回1+2+3+...+n的结果
  }
};

2.计算一年的第几天

题目来源:计算日期到天数转换

题目描述:

 根据输入的日期计算是这一年的第几天。

示例:

 输入:2021 7 18

 输出:199

思路:

 计算某日期是该年的第几天,也就是计算从该年的1月1日到该日期一共有多少天。计算总天数时,我们可以先按照平年的天数进行计算,这样一来每个月的天数都是固定的,然后再判断所给日期是否为3月及以上,因为此时才需要考虑是否为闰年,若日期为3月及以上并且为闰年,则将之前得到的总天数+1作为最终的总天数。

#include <iostream>
using namespace std;
int main()
{
  int year, month, day;
  cin >> year >> month >> day; //输入日期
  int daysArray[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; //daysArray[i]表示1月-i月的总天数(默认2月为28天)
  int totalDay = daysArray[month - 1] + day; //总天数
  if ((month > 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) //如果所给日期为3月及以上,并且该年为闰年
  {
    totalDay += 1; //总天数+1(2月29日)
  }
  cout << totalDay << endl; //输出总天数,即该日期为该年的第几天
  return 0;
}

实现二:

#include <iostream>
using namespace std;
int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int main() 
{
    int y, m, d;
    cin >> y >> m >> d;//输入年月日
    int sum = 0;
    for (int i = 1; i < m; i++) 
    { //加每月的天数
        sum += month[i - 1];
    }
    sum += d; //加日数
    if (((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) &&
            m > 2) //闰年并且月份大于2,则加一
        sum++;
    cout << sum << endl;
    return 0;
}

3.日期差值

题目来源:日期差值

题目描述:

 有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定它们之间的天数为两天。

示例:

 输入:19700101

    20210718

 输出:18827

思路:

 根据所给的两个日期,分别得到两个日期的年、月、日,然后先计算出这两个日期年相差的天数,得到的值减去第一个日期当年的天数,再加上第二个日期当年的天数即可,但是题目规定:如果两个日期是连续的,那么题目之间的天数为两天。这意味着我们需要计算的日期差值为闭区间 [date1, date2],所以输出结果时需要再加上1。

//日期差值
#include <iostream>
using namespace std;
//判断是否为闰年
bool IsLeapYear(int year)
{
  return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
  int date1, date2; //存储两个日期
  int year1, year2, month1, month2, day1, day2; //存储两个日期的年、月、日
  int ret = 0; //存储两个日期的差值
  int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //dayArray[i]代表i月的天数(平年)
  while (cin >> date1 >> date2) //多组测试数据
  {
    //确保第一个日期比第二个日期小
    if (date1 > date2)
    {
      int tmp = date1;
      date1 = date2;
      date2 = tmp;
    }
    //根据两个日期得到其年、月、日
    year1 = date1 / 10000, year2 = date2 / 10000;
    day1 = date1 % 100, day2 = date2 % 100;
    month1 = date1 % 10000 / 100, month2 = date2 % 10000 / 100;
    //计算年相差的天数
    for (int year = year1; year < year2; year++)
    {
      if (IsLeapYear(year))
        ret += 366;
      else
        ret += 365;
    }
    auto getCurYearDays = [&dayArray](int year, int month, int day)->int{
      int total = 0;
      for (int i = 1; i < month; i++) 
      {
        total += dayArray[i];
        if (i == 2 && IsLeapYear(year))
          total++;
      }
      return total + day;
    };
    //减去date1当年的天数
    int days1 = getCurYearDays(year1, month1, day1);
    ret -= days1;
    //加上date2当年的天数
    int days2 = getCurYearDays(year2, month2, day2);
    ret += days2;
    ret++; //结果为闭区间[date1, date2],所以需要再加1
    cout << ret << endl;
  }
  return 0;
}

4.打印日期

题目来源:打印日期

题目描述:

 给出年份m和一年中的第n天,计算出第n天是几月几号。

示例:

 输入:2021 100

 输出:2021-04-10

思路:

 根据得到的年份判断该年是否为闰年,从而得到该年每月的准确天数。设置月份从1月开始,判断所给总天数是否大于该年该月的总天数,若大于,则将总天数减去该月的总天数后作为新的总天数,然后将月份加一,继续进行判断;若小于,则结束判断,输出日期即可。

#include <iostream>
using namespace std;
int main()
{
  int year, day;
  int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //dayArray[i]代表i月的天数(平年)
  while (cin >> year >> day) //多组测试数据
  {
    int month = 1; //month从1月开始
    if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) //判断该年是否为闰年
      dayArray[2] += 1; //闰年2月为29天
    //使日期合法
    while (day > dayArray[month])
    {
      day -= dayArray[month];
      month++;
    }
    printf("%d-%02d-%02d\n", year, month, day); //按格式输出
  }
  return 0;
}

5. 日期累加

题目来源:日期累加

题目描述:

 设计一共程序能计算一个日期加上若干天后是什么日期。

输入描述:

 输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。

输出描述:

 输出m行每行按yyyy-mm-dd的格式输出。

示例:

 输入:2

    2021 7 18 100

    2021 1 1 100

 输出:2021-10-26

    2021-04-11

思路:

 先将需要累加的天数加到“日”上,然后通过不断的迭代使得日期合法,迭代过程如下:判断“日”是否大于该年该月的总天数,若大于,则将“日”减去该月的总天数后作为新的“日”,然后将月份加一,继续进行判断;若小于,则结束判断,输出日期即可。需要注意:每次月份加一后需要判断“年”是否需要进位,若需要进位还需判断进位后的年是否为闰年。

#include <iostream>
using namespace std;
//判断是否为闰年
bool IsLeapYear(int year)
{
  return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
  int m, year, month, day, n;
  int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //dayArray[i]代表i月的天数(平年)
  cin >> m; //读取样例个数
  for (int i = 0; i < m; i++)
  {
    cin >> year >> month >> day >> n; //读取年、月、日和需要累加的天数
    if (IsLeapYear(year))
      dayArray[2] = 29; //闰年2月设置为29天
    day += n; //先将需要累加的天数加到“日”上
    //使日期合法
    while (day > dayArray[month])
    {
      day -= dayArray[month];
      month++;
      if (month == 13) //“年”需要进位
      {
        year++;
        month = 1;
        //判断新的一年是否为闰年
        if (IsLeapYear(year))
          dayArray[2] = 29; //闰年2月设置为29天
        else
          dayArray[2] = 28; //平年2月设置为28天
      }
    }
    printf("%d-%02d-%02d\n", year, month, day); //按格式输出
  }
  return 0;
}
相关文章
|
21天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
61 19
|
21天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
41 13
|
21天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
43 5
|
21天前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
35 5
|
21天前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
43 4
|
21天前
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
31 3
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
83 2
|
2月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
145 5
|
2月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
147 4
|
2月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
218 4