C++第二作业说明文档
一.Person类:主要是对作为person成员_id,_name,_age,_totalPersons的一些初始化。
1. static int _totalPersons; 这个是静态成员变量,不属于任何一个类对象,通过类名直接调用实现。
2. 因为_id是一个标识列,在创建person类型的对象的时候,静态成员变量_totalPersons都会经行自增加操作,然后将totalPersons的值赋值给_id,对-id进行初始化.。保证每个选民都有独自的id标识列。
3. 其他的一些成员函数都是一些构造函数和析构函数,还有一些对私有成员的set和get方法,外加一个输出运算符重载,在这里不再解释。
二.PersonSet类:是一个容器,在这里面创建实现的主要有的是选民容器和候选人容器。
1.在里面不要忘记对下标运算符的重载,因为待会在候选人对象中会用到,重载的时候分为const类型和非const类型,一个常量对象,一个非常量对象,根据对象的属性选择对那个方法进行实现。
2.同时在里面需要实现”=”运算符的重载,在后面我们进行第二次或者更多次投票的时候会创建一个新的容器去放票数最高的候选人,在这里需要将新的容器对象拷贝给旧的容器对象,会用到”=”运算符的重载。这里实现的是深拷贝,这里不做解释。
三.Voter类:选民类,这里面主要实现的两个方法,一是产生随机数来获取候选人,二是实现选举功能。
1. Person& SelectCadidate(PersonSet&cadidates); 这个方法是产生随机数来获取候选人,首先传递进来一个候选人容器对象,调用这个对象的Size()方法来获取候选人的数量,赋值个变量s,然后我们使用rand()函数来产生一个随机数,这个随机数介于0-32767之间,然后通过%运算符除以s,来产生一个介于0-(s-1)之间的数字,然后通过return返回候选人容器里面的这个候选人对象。
2. Void Vote(Candidate& aCandidate );这个函数的作用是对候选人进行选举。首先上面return返回的对象是一个Person类型的引用,通过强制类型装换static_cast< Candidate &>,将person类型的引用转化为Candidate类型的引用,然后将这个引用传给aCandidate,然后这个对象调用AddVoter方法将当前这个候选人作为实参传递给形参avoter,然后通过personSet定义的对象_ps(_ps是用来存贮选民的),调用AddPerson方法来实现将当前这个选民信息添加到候选人容器里面。
3. _totalNumVoters是一个静态成员变量,用来获取参的选民人数。因为是静态成员变量,所以用类名作用域直接来实现,通过静态成员方法来返回参加的选民人数。在每一次创建Voter类型的对象的时候_totalNumVoters都会加1;
4. 这里说一下站台号,_polingStation,我们可以看到题目后面有给出相应的站台号1,2,3,但在这个题里面并没有什么作用,因为每一个站台号并不代表这相应的候选人,每个选民投的是候选人id,至于投到那个站台号的箱子里面无关重要,因为最后都是要统计起来算的,这里我们可以将站台号无视掉,或者把这个多个站台号当做一个站台号理解即可。
5. friend bool operator == (Voter& a,Voter& b);//判断两个对象是否相同,每一个参选人不能对同一个后续人投票两次。
四.Candidate类,候选人类
1.同选民类一样,在候选人类里面同样定义了一个静态的成员变量_numCandidates,用来统计比赛中候选人的人数,一些实现方法和调用方法同上。
2.Personset容器定义一个_Ps对象,用来存储选民信息。
3.Void AddVoter(Voter& aVoter);这个方法在上面的选民类中已经做了解释,就是将当前选民对象传递给形参aVoter,然后通过personSet定义的对象_ps(_ps是用来存贮选民的),调用AddPerson方法来实现将当前这个选民信息添加到候选人容器里面。至于AddPerson()方法我们在第一个作业里面已经接触过了,这里不多解释。
4. PersonSet& getPersonSet();方法用来返回Personset定义的对象_Ps。
5.剩下的都是一些get,set方法和构造函数,这里不多做说明。
6.主要讲一下这里面需要实现”<<”输出运算符重载,因为后面我们在主函数里面需要输出候选人的姓名;如果当前对象通过调用getVotesNum()方法获取到的候选人容器对象的大小为0的话,那说明没有人对当前的候选人没有进行投票操作。然后返回输出流的引用out。
7.这里面还需要对关系运算符”<”进行重载,默认的情况是c1对象的候选人容器里面的选民小于c2对象的候选人容器里面的选民大小。
五.主函数:
1.首先创建选举人,用new方法创建7个对象,用V1-V7的指针分别指向这些对象
2.定义三个候选人,方法同上。
3. PersonSet voters; PersonSet容器创建一个选民对象voters,然后voters调用AddPerson方法来将这七个对象添加到选民容器里面。
4.PersonSet candidates;,方法同上。
5. srand((unsigned int)time(NULL)); //时间参数作为种子,使用rand()函数会产生一个0~32767之间的数字。
6.下面就是对选民信息和候选人信息的一个输出显示。
7.下面进行选票,如果选民容器对象voters中选民的数量和静态成员_totalNumVoters数量一致,说明所有候选人均已投票。
8. int num1=1; 定义一个变量num1,用来统计投票的次数,我们下面可能会进行多次投票操作。
9.int maxvotesnum =0;;定义变量maxvotesnum,作用是在进行第二次第三次选举的时候,票数是在原有基础上进行叠加,为了更清楚的看到后面每次的投票情况,这里引入了maxvotesnum变量。
10.在选举之前需要将容器重置,确保每一个选民都能正常投票。
11.For里面的循环条件是选民总数,Voter& v =static_cast<Voter&>(voters.nextElement());这是一个强制类型装换,因为voters.nextElement()得到的是一个person对象,需要强制转换成Voter类型,这句实现通过遍历得到选民。
12. Candidate& chosenCandidate = static_cast<Candidate &>(v.SelectCadidate(candidates));通过上面得到的选民对象v调用SelectCadidate方法将candidates(候选人容器对象)传递acandidates,产生随机数,返回当前容器里面候选人对象赋值给chosenCandidate,一个Candidate的引用。
13. v.Vote(chosenCandidate); //选民将自己添加到候选人的选民容器,这个方法前面已经解释过。
14.While(1),循环体是1,当最后的候选人容器只有一个人的时候结束循环,输出获胜者。
15.定义一个Candidate类型的指针winner,指向候选人容器里的第一个候选人,假定第一个候选人就是最后的获胜者。
16.然后通过for循环,循环体是候选人容器的大小
17.cout<<*static_cast<Candidate*>(&candidates[i]);这里用到了运算符重载,输出候选人的姓名;
18.cout<<static_cast<Candidate*>(&candidates[i])->getVotesNum()-maxvotesnum<<endl;输出候选人的票数,减掉maxvotesnum方便看清下一次的投票情况。
19.接下来是一个if判断,这里用到了关系运算符的重载,如果后面的候选人对象的的票数大于当前的候选人对象的票数,那么后面的候选人对象就是获胜者。
20.这样会出现在一次投票下来票数相同的两个到三个候选人对象,此时我们需要进行再一次的投票选举。
21.这里需要从新定义一个PersonSet类型的容器对象 winnerCandidates;来存贮得票数最高且相同的候选人对象。
22.定义一个Candidate类型的指针_winner1,指向容器中第一个候选人对象。
23.For循环的循环体是候选人容器中候选人的数量。
24.If判断,如果候选人对象的候选人容器大小等于maxvotesnum的大小,maxvotesnum就是上一次投票后最高的票数。那么就使用winnerCandidates调用AddPerson方法把当前对象添加到候选人容器里面,进行下一次选举。
25.if判断,如果当前候选人对象的容器大小不为1,那么执行else,将当前候选人对象赋值给上一次的候选人对象,num1++进行第num1次投票。
26.If判断,如果当前候选人对象的容器大小等于1,说明只有一个票数最多的候选人,那么恭喜这个候选人获胜,输出这个候选人的姓名
27.最后因为投票者和候选人对象都是用new方法创建的,所以最后用delete释放内存空间。
-------------------------------------------------------------------------------------------------------------------
-------侯旭东
2015/8/11