C++复习:一个小例子复习基础

来源:互联网 发布:mac如何下载阿里旺旺 编辑:程序博客网 时间:2024/06/08 19:28

前言

经过两周的学习,C++基础部分基本已经有了一定的了解。正好前两天在群里看到一个哥们问了一个很有代表性的需求,于是决定以这个需求为例子,对现阶段所学知识做一个复习巩固。

需求

需求内容

游戏中有一个推荐好友的功能,每推荐成功一个玩家自己都会获得奖励,并且推荐自己的玩家也会获得一定比率的分成,同时推荐他的玩家也会获得他分成的一定比率分成,直至没有推荐者或者最小分成为止。恩,你想的没错,就是传销模式。
需求要求推荐信息以文本保存,格式如下:
1001 1002
1001 1003
1003 1004
……
每一行的前一个是推荐者的编号,后一个是被推荐者的编号。
输出信息要求如下:
1003推荐了1004 1003获得了10金币 1001获得了2金币
也就是说每一行先输出推荐信息,然后从自身开始逐级输出获得的奖励,直至结束
最后,还要求输出所有奖励的金币总数。

需求分析

这个例子虽然简单,但是包含了读取数据,存储,输出,并且数据之间还有一定的关系,并不是简单的一个容器存起来那么简单(当然,一定要这么做也可以,但是使用关联容器可能用起来更顺手)。
数据读取:比较简单,fstream可以实现。
数据存储:由于玩家人数并不固定,并且玩家需要通过编号查询,所以建立一个字典是必须的,C++中是map。当然,在这之前还需要建立一个玩家类。由于玩家可能有一个推荐者(上线),和若干个被推荐者(下线),所以上线用一个string存储,下线用一个string的vecotr容器存储,使用的时候通过该tring去字典里面获取。当然通常我们还需要保存玩家的姓名,id,由于涉及到奖励,还可以将该玩家获得的总金币数保存下来。
数据输出:这一点有点绕。由于输出的时候需要输出玩家及其所有上线的获得的奖励,而玩家有几级上线我们并不清楚,所以可以考虑使用递归来让系统自动追踪最顶级的上线,而系统的上线分成按比率逐级递减也符合这一条件。

实现

静态数据

由上述需求分析可知,推荐者获得的金币数量是固定的,上线递减比率也是固定的,金币递归的最小额度也是固定的,于是可以将其用常量存储起来方便修改。
而所有玩家(people类,下面会给出)需要通过名字进行查询,于是通过一个map<string, people>来实现。

static const int award = 25;//最大金币获得量static const double discount = 0.2;//金币获得递减比率static const int minimum = 1;//最小金币获得数量static map<string, people> AllPeople = {};//玩家字典

玩家类

玩家类中需要包含姓名,上线下线,添加下线的方法(上线在构造函数中添加,无序动态改变),以及一个递归获取金币的方法:
此处用struct,与c#中struct不同的是,c++中struct与class的唯一区别是在遇到第一个访问控制符之前,struct成员是public的,而class成员是private的,所以怎么方便怎么来,无需考虑性能的区别。

struct people{//玩家    people() = default;    people(string n) :name(n){ money = 0; }    people(string n, string p) :name(n), upPeople(p){ money = 0; }    string name;//姓名    int money;//该玩家总金币数    string upPeople;//上线    vector<string> downPeople;//下线    void addDownPeople(string p){//添加下线        downPeople.push_back(p);    }    int addMoney(int m){//递归获得金币        money += m;        cout << name << "获得了:" << m << "金币  ";        if (upPeople!=""&&(m*discount >= minimum))//递归条件            return m + AllPeople[upPeople].addMoney(static_cast<int>(m*discount));        else{//终结条件            cout << endl;            return m;        }               }};

玩家管理器类

直接调用玩家数据当然可以实现需求,但是为了方便客户端使用,降低耦合并尽量少的暴露类信息,通常使用一个管理器来对数据进行管理,客户端只需要调用管理器中对应的接口来处理数据即可。
目前管理器仅包含两个方法:添加玩家和输出金币,由于需要统计金币的总消耗量,所以需要返回一个金币值

struct peopleManager//玩家操作管理器{public:static void addPeople(string s){//根据行添加玩家int f = s.find(" ");addPeople(string(s,0,f),string(s,f+1));}static void addPeople(string up, string down){//根据玩家姓名添加玩家if (AllPeople.find(up) == AllPeople.end())AllPeople.insert({ up, people(up) });AllPeople.insert({ down, people(down, up) });AllPeople[up].addDownPeople(down);}static int appMoney(int money){//按玩家关系给予奖励int num=0;for (auto p : AllPeople)for (auto s : p.second.downPeople){cout << p.second.name << "推荐了" << s<<" ";num += p.second.addMoney(money);//递归调用}return num;}};

数据文件

由于只是练习测试用,创建一个test.txt保存在程序的根目录下,文件内容如下:
1001 1002
1001 1003
1001 1004
1002 1005
1002 1006
1003 1007
1005 1008

使用

现在准备工作做好了,我们可以使用了。
读取文件:

ifstream inFile("test.txt");//文件读取流

录入玩家数据:

string line;while (getline(inFile, line))//读取一行文件    peopleManager::addPeople(line);inFile.close();

输出金币数据:

cout <<"总金币数量为:"<< peopleManager::appMoney(award) << endl;

运行结果:
这里写图片描述

转载请注明出处:http://blog.csdn.net/ylbs110/article/details/50984578

其他

到此为止,需求已经实现了,但是实现需求本身不是目的,目的是为了在实现需求的时候巩固所学知识。
在目前的代码中,对类,函数,语句,关联容器,文件读取都有所涉及,但是对C++中具有特色的引用,指针,迭代器却并未涉及到,于是需要对代码做一些修改。

修改一:

for (auto s : p.second.downPeople){    cout << p.second.name << "推荐了" << s<<" ";    num += p.second.addMoney(money);//递归调用}   

改为

//for_each使用,迭代器使用,lambda使用,引用,指针for_each(p.second.downPeople.begin(),p.second.downPeople.end(),[&p, &num, money](string s){cout << p.second.name << "推荐了" << s << " "; num += p.second.addMoney(money); });

这么一改,复习了泛型方法,迭代器,指针,引用。具体用法我就不细细分析了,自己查询一下也可以加深印象。

修改二:

由于每个玩家的下线玩家不会重复,所以可以采取set而不是vector。

    vector<string> downPeople;//下线    void addDownPeople(string p){//添加下线        downPeople.push_back(p);    }

改为

    set<string> downPeople;//下线    void addDownPeople(string p){//添加下线        downPeople.insert(p);    }

修改三:

将people除默认构造方法外改为私有,通过友元来让玩家管理器调用,这样复习了友元,代码也更加符合开闭原则:

struct people{//玩家    friend class peopleManager;//友元使用    people() = default;private:    people(string n) :name(n){ money = 0; }    people(string n, string p) :name(n), upPeople(p){ money = 0; }    string name;//姓名    int money;//该玩家总金币数    string upPeople;//上线    vector<string> downPeople;//下线    void addDownPeople(string p){//添加下线        downPeople.push_back(p);    }    int addMoney(int m){//递归获得金币        money += m;        cout << name << "获得了:" << m << "金币  ";        if (upPeople!=""&&(m*discount >= minimum))//递归条件            return m + AllPeople[upPeople].addMoney(static_cast<int>(m*discount));        else{//终结条件            cout << endl;            return m;        }               }};

所有代码

#include "stdafx.h"#include <iostream>#include <string>#include <map>#include <set>#include <vector>#include <fstream>#include <algorithm>using namespace std;struct people;struct peopleManager;static const int award = 25;//最大金币获得量static const double discount = 0.2;//金币获得递减比率static const int minimum = 1;//最小金币获得数量static map<string, people> AllPeople = {};//玩家字典struct people{//玩家    friend struct peopleManager;//友元使用    people() = default;    ~people(){}private:    people(string n) :name(n){ money = 0; }    people(string n, string p) :name(n), upPeople(p){ money = 0; }    string name;//姓名    int money;//该玩家总金币数    string upPeople;//上线    set<string> downPeople;//下线    void addDownPeople(string p){//添加下线        downPeople.insert(p);    }    int addMoney(int m){//递归获得金币        money += m;        cout << name << "获得了:" << m << "金币  ";        if (upPeople!=""&&(m*discount >= minimum))//递归条件            return m + AllPeople[upPeople].addMoney(static_cast<int>(m*discount));        else{//终结条件            cout << endl;            return m;        }               }};struct peopleManager//玩家操作管理器{public:    static void addPeople(string s){//根据行添加玩家        int f = s.find(" ");        addPeople(string(s,0,f),string(s,f+1));    }    static void addPeople(string up, string down){//根据玩家姓名添加玩家        if (AllPeople.find(up) == AllPeople.end())            AllPeople.insert({ up, people(up) });        AllPeople.insert({ down, people(down, up) });        AllPeople[up].addDownPeople(down);    }    static int appMoney(int money){//按玩家关系给予奖励        int num=0;        for (auto p : AllPeople)            for_each(p.second.downPeople.begin(),p.second.downPeople.end(),//for_each使用,迭代器使用                [&p, &num, money](string s){cout << p.second.name << "推荐了" << s << " "; num += p.second.addMoney(money); }//lambda使用            );            //for (auto s : p.second.downPeople){            //  cout << p.second.name << "推荐了" << s<<" ";            //  num += p.second.addMoney(money);//递归调用            //}                     return num;    }};int _tmain(int argc, _TCHAR* argv[]){    string line;    ifstream inFile("test.txt");//文件读取流    while (getline(inFile, line))//读取一行文件        peopleManager::addPeople(line);    inFile.close();    cout <<"总金币数量为:"<< peopleManager::appMoney(award) << endl;      return 0;}
1 0
原创粉丝点击