Accelerated C++学习笔记5―(组织程序和数据)(二)

2014-11-24 13:11:03 · 作者: · 浏览: 15
W9zobE6IM7et6i3w87KIHByaXZhdGUgs8nUsSjU2qGwc3RkOjqhozwvc3Ryb25nPgo8YnI+CgoyoaLX6davyv2+3Qq8xsvj0ru49tGnyfq1xLPJvKi21NXiuPbRp8n6wLTLtcrHutzT0NPDtcSjrLK7uf3V4rj2vMbL48qut9a88rWlo6y21NPavczK2sC0y7WjrM7Sw8e4/M+jzfu1xMrH0qq8xsvjs/bSu9X7sODRp8n6tcSzybyoo6zV4tH5ztLDx8+jzfuwtNXV0afJ+rXE0NXD+7XE19bEuMuz0PLAtNfp1q/K5LP2saix7aOstvjH0s7Sw8fPo837193P8sXFwdDX3LPJvKjS1LHj09rUxLbBo6zL+dLU1eK+zdKqx/PO0sPH0OjSqtPQ0ru49rXYt73AtLSitObL+dPQ0afJ+rXEvMfCvKOs1eLR+c7Sw8e+zb/J0tSwtNfWxLjLs9DywLTFxcHQy/vDx8HLo6y7udDo0qrM2LHw16LS4rXEysfOqsHLyLe2qNTaw7/Su7j20NXD+7rNttTTprXEs8m8qNauvOTSqrfF1sO24MnZuPa/1SYjMjY2ODQ7o6zO0sPHu7nSqtXSs/bX7rOktcTQ1cP7tcSzpLbIoaMKMaOpsNHL+dPQtcTRp8n6tcTL+dPQyv2+3bfF1sPU2tK7xvAKPHByZSBjbGFzcz0="brush:java;">struct Student_info { string name; double midterm, final; vector homework; };//这里一定要注意分号是不可缺少的
程序说明: 1)Student_info是一种具有四个数据成员的类型,因为Strudent_info是一种类型,所有我们就可以定义这种类型的对象,而每一个对象都会包含这四个数据成员的一个实例。 2)每一个Student_info类型的对象都保存了一个学生的信息,因为Student_info是一种类型,我们用一个vctor 类型来保存任意数目的学生的信息,这就好像相当于我们之前使用一个vector 类型的对象来保存任意数目的家庭作业成绩一样。 3)这里还需要注意结尾的那个分号是不可缺少的。
2)处理学生记录 简单思路:①我们要把数据读到一个Student_info类型的对象中;②要为一个Student_info类型的对象生成总成绩。③找到一种方法对一个Student_info类型的向量进行排序。 ①读入并储存学生的姓名以及期中、期末考试成绩
//需要读学生的姓名以及考试成绩
istream& read(istream& is, Student_info& s)
{
	is >> s.name >> s.midterm >> s.final;

	read_hw(is, s.homework);//读入并储存学生的所有家庭作业成绩
	return is;
}

程序说明: read函数具有两个引用,一个是istream,我们就是从istream中读数据的;另一个引用则是一个对象,它储存了函数所读到的数据,在函数内部使用参数s的时候,我们会影响传递给我们的那个参数的状态。
②为Student_info类型的对象计算总成绩
double grade(const Student_info& s)
{
    return grade(s.midterm, s.fianl, s.homework);
}

程序说明: 注意参数类型是const Student_info&而不是简单Student_info,这样的话,在我们调用它的时候就不会有复制整个Student_info对象而带来的额外开销了。
③对Student_info类型的对象进行排序 这里要注意不可以使用
sort(student.begin(), student.end());

因为sort试图去比较两个这样的对象的话,编译器会报错。
所以我们必须引入第三个参数
// 按字母顺序排列学生记录
bool compare(const Student_info& x, const Studnt_info& y)
{
     return x.name < y.name;
}
sort(students.begin(), students.end(), compare);

这里编写的比较函数仅仅是对名字进行比较。
3)生成报表
int _tmain(int argc, _TCHAR* argv[])
{
	vector
       
         students; Student_info record; string::size_type maxlen = 0; //最长的姓名的长度 //读入并存储所有学生的数据 //不变式 // students 包含了所有的学生的记录 // max包含了students中最长的姓名 while (read(cin, record)) //找出最长的姓名的长度 { maxlen = max(maxlen, record.name.size()); students.push_back(record); } // 按字母顺序排列学生记录 sort(students.begin(), students.end(), compare); //输出姓名和成绩 for (std::vector
        
         ::size_type i = 0; j != students.size(); ++i) { //输出姓名,把姓名填充至maxlen + 1 个字符长度 cout << setw(maxlen+1) << students[i].name; //计算并输出成绩 try { double final_grade = grade(students[i]); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec); } catch(domain_error e) { cout << e.what(); } cout << endl; } return 0; }
        
       

程序说明: 1)库函数中max在头文件 中定义了,表明上max的行为是很明显的,但是它的行为的其中一方面是不明显的,由于某些复杂的原因,它的两个参数必须具备同样的类型,所以我们把它maxlen定义为int类型是不合适的,那么我们必须把它定义为一个string::size_type类型的变量; 2)原先计算成绩中我们使用了setprecision;setw的工作方式与之相似,setw来控制输出流的格式,这里用setw来确保输出中每一个姓名都会消耗跟输入中的最长的姓名一样多的字符,同时它还会用一个额外的空格来作为姓名与成绩之间的空白。,不同的地方在于对宽度的修改是短暂的,每一个标准输出运算符在完成了它的输出动作之后就马上回重置流的宽度。代码中作用就是为name填充字符,同时输出name的运算符将把流的宽度重置为0。
3、把各部分代码连接在一起 目前为止,我们已经定义了很多抽象函数,这些抽象函数对于解决各种成绩问题都是很有用的,我们以前使用这些函数的方法就是把他们所有的定义都放在同一个文件中并编译文件,很明显这个方法很快会变得越来越复杂 1)学会组装函数 例如组装median函数
//median函数的源文件
#include "stdafx.h"
#include 
        
          //获取sort声明 #include 
         
           //获取domain_error的声明 #include 
          
            //获取vector的声明 using namespace std; //计算一个vector
           
            类型的对象的中值 { typedef vector
            
             ::size_type vec_sz; vec_sz size = vec.size(); if(size == 0) throw domain_error(