第4章 类与对象

目录

第1关:CPU类

任务描述

相关知识

面向对象程序设计的基本特点

抽象

封装

类和对象

类和对象的关系

类定义的语法形式

类成员的访问控制

对象定义的语法

类中成员互相访问

类外访问

类内初始值

类的成员函数

内联成员函数

构造函数

构造函数的作用

构造函数的形式

析构函数

实验步骤

测试说明

代码

第2关:Computer类

任务描述

相关知识

类的组合

组合的概念

类组合的构造函数设计

构造组合类对象时的初始化次序

前向引用声明

任务要求

测试说明

代码


第1关:CPU类

任务描述

声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,有两个公有成员函数run、stop。其中,rank 为枚举类型CPU_Rank,声明为enum CPU_Rank {P1=1,P2,P3,P4,P5,P6,P7},frequency为单位是MHz 的整型数,voltage 为浮点型的电压值。观察构造函数和析构函数的调用顺序。

相关知识

为了你能够更好的完成本关任务,你需要掌握

  1. 面向对象程序设计的基本特点;
  2. 类和对象;
  3. 构造函数和析构函数。
面向对象程序设计的基本特点
抽象

对同一类对象的共同属性和行为进行概括,形成类。

  • 先注意问题的本质,其次是实现过程或细节。
  • 数据抽象:描述某类对象的属性或状态(对象相互区别的物理量)。
  • 代码抽象:描述某类对象的共有的行为特征或具有的功能。
  • 抽象的实现:类。 抽象实例——钟表 class Clock { public: void setTime(int newH, int newM, int newS); void showTime(); private: int hour, minute, second; };
封装

将抽象出的数据、代码封装在一起,形成类。

  • 目的:增强安全性和简化编程,使用者不必了解具体的实现细节,而只需要通过外部接口,以特定的访问权限,来使用类的成员;
  • 实现封装:类声明中的{}。 class Clock { public: void setTime(int newH, int newM, int newS); void showTime(); private: int hour, minute, second; };
类和对象
类和对象的关系
  • 对象是现实中的对象在程序中的模拟;
  • 类是同一类对象的抽象,对象是类的某一特定实体;
  • 定义类的对象,才可以通过对象使用类中定义的功能。
类定义的语法形式

class 类名称 { public: 公有成员(外部接口) private: 私有成员 protected: 保护型成员 }

类成员的访问控制
  • 公有类型成员 在关键字public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数;
  • 私有类型成员 在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。如果紧跟在类名称的后面声明私有成员,则关键字private可以省 略;
  • 保护类型成员 与private类似,其差别表现在继承与派生时对派生类的影响不同。
对象定义的语法

类名 对象名; 例:Clock myClock;

类中成员互相访问

直接使用成员名访问

类外访问

使用“对象名.成员名”方式访问 public 属性的成员

例:钟表类 类的定义

 
  1. #include<iostream>
  2. using namespace std;
  3. class Clock{
  4. public:
  5. void setTime(int newH = 0, int newM = 0, int newS = 0);
  6. void showTime();
  7. private:
  8. int hour, minute, second;
  9. }
  10. 成员函数的实现
  11. void Clock::setTime(int newH, int newM, int newS) {
  12. hour = newH;
  13. minute = newM;
  14. second = newS;
  15. }
  16. void Clock::showTime() {
  17. cout << hour << ":" << minute << ":" << second << endl;
  18. }
  19. 对象的使用
  20. int main() {
  21. Clock myClock;
  22. myClock.setTime(8, 30, 30);
  23. myClock.showTime();
  24. return 0;
  25. }

运行结果: 8:30:30

类内初始值
  • 可以为数据成员提供一个类内初始值
  • 在创建对象时,类内初始值用于初始化数据成员
  • 没有初始值的成员将被默认初始化。 类内初始值举例 class Clock { public: void setTime(int newH, int newM, int newS); void showTime(); private: int hour = 0, minute = 0, second = 0; };
类的成员函数
  • 在类中说明函数原型;
  • 可以在类外给出函数体实现,并在函数名前使用类名加以限定;
  • 也可以直接在类中给出函数体,形成内联成员函数;
  • 允许声明重载函数和带默认参数值的函数。
内联成员函数
  • 为了提高运行时的效率,对于较简单的函数可以声明为内联形式。
  • 内联函数体中不要有复杂结构(如循环语句和switch语句)。
  • 在类中声明内联成员函数的方式: 将函数体放在类的声明中。 使用inline关键字。
构造函数

定义对象时,如何进行初始化呢?对象的初始化方法需要在程序中规定好,为此,C++语法提供了一个特殊的机制——构造函数。

构造函数的作用

在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态。 例如:希望在构造一个Clock类对象时,将初始时间设为0:0:0,就可以通过构造函数来设置。

构造函数的形式
  • 函数名与类名相同;
  • 不能定义返回值类型,也不能有return语句;
  • 可以有形式参数,也可以没有形式参数;
  • 可以是内联函数;
  • 可以重载;
  • 可以带默认参数值。
析构函数
  • 完成对象被删除前的一些清理工作;
  • 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间;
  • 如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数,其函数体为空。

例:构造函数和析构函数

 
  1. #include <iostream>
  2. using namespace std;
  3. class Point {
  4. public:
  5. Point(int xx,int yy);
  6. ~Point();
  7. //...其他函数原型
  8. private:
  9. int x, y;
  10. };
  11. Point::Point(int xx,int yy)
  12. {
  13. x = xx;
  14. y = yy;
  15. }
  16. Point::~Point() {
  17. }
  18. //...其他函数的实现略

实验步骤

编写一个CPU类,并将代码补充在右侧任务挑战区 Begin-End 之间。

测试说明

根据提示,在右侧编辑器补充代码,并保持类已有的结构。 平台会对你编写的代码进行测试,程序输出应为: 构造了一个CPU! CPU开始运行! CPU停止运行! 析构了一个CPU!

代码
#include <iostream>
using namespace std;

enum CPU_Rank {P1=1,P2,P3,P4,P5,P6,P7};
class CPU
{
private:
    CPU_Rank rank;
    int frequency;
    float voltage;
public:
    CPU (CPU_Rank r, int f, float v)
    {
        /********** Begin **********/
        rank = r;
        frequency = f;
        voltage = v;
        cout << "构造了一个CPU!" << endl;
        /********** End **********/
    }
    ~CPU () { 
        /********** Begin **********/
        cout << "析构了一个CPU!" << endl;
        /********** End **********/
    }

    CPU_Rank GetRank() const { return rank; }
    int GetFrequency() const { return frequency; }
    float GetVoltage() const { return voltage; }

    void SetRank(CPU_Rank r) { rank = r; }
    void SetFrequency(int f) { frequency = f; }
    void SetVoltage(float v) { voltage = v; }

    void Run() {
        /********** Begin **********/
        cout << "CPU开始运行!" << endl;
        /********** End **********/
    }
    void Stop() {
        /********** Begin **********/
        cout << "CPU停止运行!" << endl;
        /********** End **********/
    }
};

int main()
{
    CPU a(P6,300,2.8);
    a.Run();
    a.Stop();
}

第2关:Computer类

任务描述

声明一个简单的Computer类,有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,有两个公有成员函数run、stop。cpu 为CPU类的一个对象,ram为RAM 类的一个对象,cdrom为CDROM 类的一个对象,声明并实现这个类。

相关知识

为了你能够更好的完成本关任务,你需要掌握

  1. 类的组合。
类的组合
组合的概念
  • 类中的成员是另一个类的对象;
  • 可以在已有抽象的基础上实现更复杂的抽象。
类组合的构造函数设计
  • 原则:不仅要负责对本类中的基本类型成员数据初始化,也要对对象成员初始化。
  • 声明形式: 类名::类名(对象成员所需的形参,本类成员形参) :对象1(参数),对象2(参数),...... { //函数体其他语句 }
构造组合类对象时的初始化次序
  • 首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,初始化次序是成员在类体中定义的次序; 成员对象构造函数调用顺序:按对象成员的声明顺序,先声明者先构造; 初始化列表中未出现的成员对象,调用用默认构造函数(即无形参的)初始化;
  • 处理完初始化列表之后,再执行构造函数的函数体。

例:类的组合,线段(Line)类

 
  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. class Point {//Point类定义
  5. public:
  6. Point(int xx = 0, int yy = 0) {
  7. x = xx;
  8. y = yy;
  9. }
  10. Point(Point &p);
  11. int getX() { return x; }
  12. int getY() { return y; }
  13. private:
  14. int x, y;
  15. }
  16. Point::Point(Point &p) { //复制构造函数的实现
  17. x = p.x;
  18. y = p.y;
  19. cout << "Calling the copy constructor of Point" << endl;
  20. }
  21. //类的组合
  22. class Line { //Line类的定义
  23. public: //外部接口
  24. Line(Point xp1, Point xp2);
  25. Line(Line &l);
  26. double getLen() { return len; }
  27. private: //私有数据成员
  28. Point p1, p2;//Point类的对象p1,p2
  29. double len;
  30. }
  31. //组合类的构造函数
  32. Line::Line(Point xp1, Point xp2) : p1(xp1), p2(xp2) {
  33. cout << "Calling constructor of Line" << endl;
  34. double x = static_cast<double>(p1.getX() - p2.getX());
  35. double y = static_cast<double>(p1.getY() - p2.getY());
  36. len = sqrt(x * x + y * y);
  37. }
  38. Line::Line (Line &l): p1(l.p1), p2(l.p2) {//组合类的复制构造函数
  39. cout << "Calling the copy constructor of Line" << endl;
  40. len = l.len;
  41. }
  42. //主函数
  43. int main() {
  44. Point myp1(1, 1), myp2(4, 5); //建立Point类的对象
  45. Line line(myp1, myp2); //建立Line类的对象
  46. Line line2(line); //利用复制构造函数建立一个新对象
  47. cout << "The length of the line is: ";
  48. cout << line.getLen() << endl;
  49. cout << "The length of the line2 is: ";
  50. cout << line2.getLen() << endl;
  51. return 0;
  52. }

运行结果如下: Calling the copy constructor of Point Calling the copy constructor of Point Calling the copy constructor of Point Calling the copy constructor of Point Calling constructor of Line Calling the copy constructor of Point Calling the copy constructor of Point Calling the copy constructor of Line The length of the line is: 5 The length of the line2 is: 5

前向引用声明
  • 类应该先声明,后使用;
  • 如果需要在某个类的声明之前,引用该类,则应进行前向引用声明;
  • 前向引用声明只为程序引入一个标识符,但具体声明在其他地方;
  • 注意

    使用前向引用声明虽然可以解决一些问题,但它并不是万能的。 在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象。 当使用前向引用声明时,只能使用被声明的符号,而不能涉及类的任何细节。

例: class B; //前向引用声明 class A { public: void f(B b); }; class B { public: void g(A a); };

例: class Fred; //前向引用声明 class Barney { Fred x; //错误:类Fred的声明尚不完善 }; class Fred { Barney y; };

任务要求

编写一个Computer类,并将代码补充在右侧的任务挑战区 Begin-End 之间。

测试说明

根据提示,在右侧编辑器补充代码,保持类的结构。 平台会对你编写的代码进行测试,程序输出应为: 构造了一个Computer! Computer开始运行! CPU开始运行! RAM开始运行! CDROM开始运行! Computer停止运行! CPU停止运行! RAM停止运行! CDROM停止运行! 析构了一个Computer!

代码
#include <iostream>
using namespace std;

class CPU
{
public:
    CPU (){}
    ~CPU () {}
    void Run() {cout << "CPU开始运行!" << endl; }
    void Stop() {cout << "CPU停止运行!" << endl; }
};

class RAM
{
public:
    RAM () {}
    ~RAM () {}
    void Run() {cout << "RAM开始运行!" << endl; }
    void Stop() {cout << "RAM停止运行!" << endl; }
};

class CDROM
{
public:
    CDROM () {}
    ~CDROM () {}
    void Run() {cout << "CDROM开始运行!" << endl; }
    void Stop() {cout << "CDROM停止运行!" << endl; }
};

class Computer
{
private:
    CPU cpu;
    RAM ram;
    CDROM cdrom;
public:
    Computer (CPU c, RAM r, CDROM cd)
    {
        cpu = c;
        ram = r;
        cdrom = cd;
        cout << "构造了一个Computer!" << endl;
    }
    ~Computer () {cout << "析构了一个Computer!" << endl; }

    CPU GetCPU() const { return cpu; }
    RAM GetRAM() const { return ram; }
    CDROM GetCDROM() const {return cdrom; }

    void setCPU(CPU c) { cpu = c; }
    void setRAM(RAM r) { ram = r; }
    void setCDROM(CDROM cd) { cdrom = cd; }

    void Run() {
        cout << "Computer开始运行!" << endl;
        /********** Begin **********/
        cpu.Run();
        ram.Run();
        cdrom.Run();
        /********** End **********/
    }

    void Stop () {
        cout << "Computer停止运行!" << endl;
        /********** Begin **********/
        cpu.Stop();
        ram.Stop();
        cdrom.Stop();
        /********** End **********/
    }
};

int main() {
    CPU c;
    RAM r;
    CDROM cd;
    Computer computer(c, r, cd);
    computer.Run();
    computer.Stop();
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小柒_02

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值