(构造函数与静态成员)火星战士自主进攻

任务描述

本关任务:仿真和游戏中经常有计算机生成的兵力,从诞生开始就有一定的自主行为。请为火星战士设计和定义类Martian,使得每产生一个对象,就会按规则判断等待还是进攻。具体要求如下:

Martian类的基本属性:

  • string name; // 火星战士的名字
  • int mCount; //当前系统中存活的火星战士总数(消亡时需要减掉)
  • int id //火星战士的流水号(只加不减,保证是唯一的ID,不会与消亡的重号)
  • int mid //火星战士的身份证号(每个火星战士的身份证号是唯一的)

Martian类的功能:

(1) 构造函数: 每构造一个对象时,更新mCount和id,并把id赋值给mid,按以下规则命名对象,再调用Attack()函数 对象命名规则:

  • 若用参数指定名字,则按指定名字命名对象;
  • 若无参数,则用"MARTIAN"拼接上id做后缀命名对象;
  • 若通过已有对象构造,则按已有对象的名字拼接上id做后缀命名新对象。

(2)析构函数

每个对象消亡前,输出自己的name “was killed! Now alive ”, 更新 mCount并输出;例如:superman was killed! Now alive 6

(3) int getCount() 返回当前系统中火星战士的总数 (4)int getId() 返回火星战士流水号,即历史上一共产生了多少战士 (5)int getMId() 返回火星战士的身份证号mid (6)void Attack() 若当前系统中火星战士的总数>=5, 则输出自己的名字和“Attack!”, 否则输出自己的名字和“Wait!” (7)void rename(string s) 改名为s+mid (8)void rename(const Martian &m) 改名为m的名字+mid

解题思路

  • 为所有对象共享,共同维护的数据成员应设为static(静态数据成员),例如火星战士总数和流水号, 静态数据成员必须在类外初始化
  • 为所有对象共享,仅涉及静态数据成员的函数,可设为静态成员函数
  • 每生成一个对象,需要执行的操作,可放于构造函数
  • 每个对象消亡导致的操作,可放于析构函数

探索发现

请在集成开发环境中运行整个程序,阅读主函数,对比分析输出内容,思考以下问题 1 最后一个消亡的对象是谁? 2 观察Declare Martian in loop后面的输出,体会循环语句的块作用域 3 观察2 copies of superman in function后面的输出,这是调用copy2函数产生的2个sm, 体会函数的作用域 4 体会构造函数和析构函数何时被调用 5 观察生成火星战士名字后缀,以及当前的火星战士总数,体会静态成员的价值和使用 6 学习对象指针和对象数组的使用与初始化 7 为什么程序结束后,仍然有几个活着的火星战士?如何改进?体验内存溢出的潜在风险 8 为什么要用静态成员计数, 而不用全局计数器呢? 从类的封装性的角度思考一下,对于更复杂的场景,不仅仅有火星战士,还有更多类型的士兵,或者同时有多个用户、或者多个函数、多个进程都可能产生火星战士,使用全局计数器是否存在安全隐患?

编程要求

根据提示,在右侧编辑器补充代码实现类,保证主函数运行正确。

测试说明

平台会对你编写的代码进行测试:

测试输入:3;  

预期输出:

 
  1. globalMartian wait!
  2. MARTIAN2 wait!
  3. MARTIAN3 wait!
  4. MARTIAN4 wait!
  5. --------------------
  6. Declare Martian in 3 loop
  7. MARTIAN5 attack!
  8. MARTIAN5 was killed! Now alive 4
  9. MARTIAN6 attack!
  10. MARTIAN6 was killed! Now alive 4
  11. MARTIAN7 attack!
  12. MARTIAN7 was killed! Now alive 4
  13. --------------------
  14. Superman is coming
  15. superman attack!
  16. --------------------
  17. 2 copies of superman in function
  18. superman9 attack!
  19. superman10 attack!
  20. superman10 was killed! Now alive 6
  21. superman9 was killed! Now alive 5
  22. --------------------
  23. hero and it's avatar are coming
  24. hero attack!
  25. hero was killed! Now alive 5
  26. --------------------
  27. killer attack!
  28. angel attack!
  29. king attack!
  30. --------------------
  31. killed:6
  32. alive:8
  33. game is over
  34. king was killed! Now alive 7
  35. angel was killed! Now alive 6
  36. killer was killed! Now alive 5
  37. superman was killed! Now alive 4
  38. globalMartian was killed! Now alive 3

开始你的任务吧,祝你成功!

答案

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

class Martian
{
    //此外完成类的定义,成员函数只写原型
    /BEGIN/
public:
    Martian();//默认构造函数,更新mCount和id,起名为MARTIAN加id后缀,调attack
    Martian(string s);// 带参数的构造函数,更新mcount和id,起名为s加id后缀,调attack
    Martian(const Martian &m);//复制构造函数,基于m构造新对象,更新mCount和id,起名为m的:
    inline static int getCount();//静态成员函数 返回总数
    inline static int getId();//静态成员函数 返回流水号
    void rename(const Martian& m);//改成m的名字加id后缀void rename(string s);// 改名为s加id后缀
    void rename(string s);
    void attack();//若当前存活的总数超过5个,则攻击,否则等待
    ~Martian();//输出被杀死的信息,更新mcount
private:
    string name;//名字
    int mid;
    static int id;// 流水号
    static int mCount;//存活的总数

    end
};

//以下两段代码供参考,学习使用<string>库提供的函数和重载的运算符
void Martian::rename(const Martian &m) // 改名为m的名字加mid作后缀
{
    this->name = m.name + to_string(mid); // +运算能够实现拼接;  to_string函数能够将整型转换成string对象  
}
void Martian::rename(string s) // 改名为s加mid作后缀
{
    this->name = s + to_string(mid);
}
// 请在如下BEGIN-----end之间完成静态数据成员的初始化,并实现Martian类的其余成员函数
//BEGIN/
int Martian::mCount = 0;
int Martian::id = 0;

Martian::Martian()//默认构造函数,存活的总数+1,流水号+1,起名为MARTIAN+编号,attack
{
    mCount++; id++;
    name = "MARTIAN" + to_string(id);
    mid = id;
    attack();
}
Martian::Martian(string s)//带参数的构造函数,计数器加1,用参数s定制构造,进攻
{
    name = s;
    mCount++; id++;
    mid = id;
    attack();
}
Martian::Martian(const Martian& m)//复制构造函数,照着对象m定制构造,计数器加1,名字加编号
{
    mCount++; id++;
    mid = id;
    name = m.name + to_string(mid);
    attack();
}

Martian::~Martian()
{
    mCount--;//析构函数,计数器减1
    cout << name << " was killed! Now alive " << mCount << endl;
}

inline int Martian::getCount()
{
    return mCount;
}
inline int Martian::getId()
{
    return id;
}

void Martian::attack()
{
    if (mCount >= 5) cout << name << " attack!\n";
    else cout << name << " wait!\n";
}

end

void copy2(const Martian &m)//自定义的普通函数,复制生成2个m
{
    Martian s[2] = { Martian(m),Martian(m)};
}

Martian gm("globalMartian"); // 声明全局对象,拥有文件作用域
int main()
{
    Martian* p;
    int n;
    cin >> n;
    p = new Martian[n];  // 动态分配内存,生成n个缺省战士


    cout << "--------------------\n";
    cout << "Declare Martian in 3 loop\n";
    for (int i = 0; i < 3; i++)
    {
        Martian m;  //注意作用域,每轮循环生成1个缺省战士,但进入下一轮循环前就消亡,
    }

    cout << "--------------------\n";
    cout << "Superman is coming\n";
    Martian sm("superman");  // 生成superman
    cout << "--------------------\n";
    cout << "2 copies of superman in function\n";
    copy2(sm);  //复制生成2个sm  注意函数的块作用域

    cout << "--------------------\n";
    cout << "hero and it's avatar are coming\n";
    { Martian h1("hero"); } // 生成hero和替身 注意作用域

    cout << "--------------------\n";

    Martian marray[3] = { Martian("killer"), Martian("angel"), Martian("king") }; //声明对象数组,系统自动调用默认构造函数
    cout << "--------------------\n";
    cout << "killed:" << (Martian::getId() - Martian::getCount()) << endl; // 消亡的总数
    cout << " alive:" << Martian::getCount() << endl; //直接调用静态成员函数显示当前总个数

    cout << "game is over\n";//注意消亡的顺序

    return 0;

}

用于本人在大学期间的学习记录

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值