第九章

第九章(定义新类型)

Duang~duang~duang一下,代码就好了

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

istream& read(istream& in)

{

       in>> name >> midterm >> final ;

       read_hw(in,homework);

       returnin;

}

double student_info::grade() const{

          return::grade(midterm, final, homework);

}

bool compare (const student_info& x,const student_info& y)

{

       returnx.name() < y.name();

}

class student_info {

public:

   //类型提供的接口

       doublegrade() const;      //获得成绩

       boolvalid() const{return !homework, empty();}      // 判断家庭作业成绩是否为空

       std::istream&read(std::istream&);         //  输入

       std::stringname() const{return n;}        //获取名字,以便按名字排序和输出

private:

   //类型的实现

       std::stringname;

       doublemidterm, final;

       std::vector<double>homework;

};

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

这个代码是将之前那个结构体写成类之后的样子 ,是不是变化很大呀,来一一分析吧。

首先是类的主体,我们希望将数据成员隐藏起来并允许用户仅仅通过我们的成员函数访问这些数据,以便对数据成员进行保护。

     C++这类保护机制中有保护标示符public(公有的)和private(私有的),(还有其他的后面再讲)其中类型的用户都可以访问公有成员:私有成员对类型用户来说是不可访问的。

     使用struct和class的差别是:如果在第一个保护标示符之前有成员,对于class来说访问限制默认是私有的,对于struct来说访问限制是公有的。仅此容易哦~~

     那我们来分析其中的成员函数。

首先是那个read函数,我们与之前的代码比较发现:

1.      函数名student_info::read而不是read  (解释: ::是一个作用域运算符表示这个函数是此类型的成员函数)

2.      由于这个函数是student_info对象的一个成员,因此我们不需要将一个student_info类型的对象作为参数进行传递。(在运用中假如我们用了对象s,我们使用一个成员函数就要写出这个对象,例如s.read(),函数的参数隐含在对象中了,这里就是s)

3.      我们直接访问对象的数据元素,例如我们之前引用了s.midterm而这里我们只是引用了midterm。(在read内部引用成员无需使用限定形式,这是由于我们引用的是那个正在由我们操作的对象的成员)

grade()函数,我们并不陌生,但却发生了变化,不仅去掉了参数,而且后面还跟着const(常量)的小尾巴,怎回事呢?因为我们将grade定义为student_info类的一个成员,这个函数便隐含的引用了一个该类型的对象,而不需要限定形式来访问这个对象的成员。关于const,我们在原来的程序中在传递student_info时,我们将它当做一个const(常量)引用。这样就保证该操作不会改变该值,但是放在这个函数中,参数是隐含的,我们无法用const来声明,相反,我们对函数本身做限制,这样就能将它设置成一个常量成员函数。保证数据不会被修改。

这里面我们未见过面的函数是那个bool型的valid函数,那么它是做什么用的呢?试想一下如果用户未调用read函数就调用了grade函数会出现什么?因为我们还没有为向量赋值,因此grade调用会产生一个异常,因此我们有必要再调用grade之前检查是否有潜在的异常。

9.5构造函数

当我们定义一个字符串或向量对象时,如果我们不指定初始值,就会得到一个空的字符串或向量。同理,我们自己定义的类也要有这些功能,构造函数的意义便在于此。

构造函数是一个特殊的成员函数,它定义了对象的初始化方式,构造函数不能显式调用,而是在定义一个类对象时被自动调用。

。。。。中间的部分太过冗长,果断略过(p169),主要是介绍如果不写构造函数会怎样。

需要注意不时凡是库类型定义的都会自动初始化,因为库提供了他们初始化的构造函数。但是内部类型就会被给一个未定义的值(分配内存单元原来是什么就是什么,通常是错误的)

我们希望构造两个构造函数,一个是默认构造函数,一个是带参数的构造函数(对输入流的引用)。如下:

student_info  s;    、、空对象

student_info   s2(cin) 、、从cin读数据,初始化s2

构造函数与其他成员函数有两点不同之处:它的名称和类本身的名称相同;他们没有返回值类型。

构造函数也可以重载。

默认构造函数,不带参数的构造函数被称为默认构造函数,它的工作通常是保证对象的数据成员被正确的初始化,对于student_info来说,name和vector<double>homework是自动初始化的,所以剩下的double类型的midterm和final需要我们显式的初始化。如下:

student_info::student_info():midterm(0),final(0){}

要注意形式,还有midterm和final是被显式初始化的,n和homework是隐式初始化的。

当我们建立对象后是这样的过程:

1.  实现分配内存以保存对象

2.  按照构造函数初始化程序列表而对对象进行初始化

3.  执行构造函数函数体

带参数的构造函数

student_info::student_info(istream&is){read(is);}

这个构造函数把初始化的任务交给read函数去完成了。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#include<iostream>

#include<iomanip>

#include<algorithm>

#include<string>

#include<vector>

#include<ios>

 

using namespace std;

 

class student_info {

public:

       doublegrade() const;

       boolvalid() const{return !homework.empty();}

       istream&read(std::istream&);

       stringname() const{return n;}

       student_infos;             

       student_infos2(cin);   

private:

       stringn;

       doublemidterm, final;

       std::vector<double>homework;

};

student_info::student_info():midterm(0),final(0) {}  //无参

student_info::student_info(istream&is){read(is);}  //有参

istream& read(istream& in)

{

       in>> n >> midterm >> final ;

       read_hw(in,homework);

       returnin;

}

double student_info::grade() const{

          return::grade(midterm, final, homework);

}

bool compare (const student_info& x,const student_info& y)

{

       returnx.name() < y.name();

}

int main()

{

       vector<student_info>students;

       student_inforecord;

       string::size_typemaxlen = 0;

       while(record.read(cin)){

              maxlen= max(maxlen, record.name().size());

              student.push_back(record);

       }

       sort(students.begin(),students.end(), compare);

       for(vector<student_info>::size_typei = 0;i != student.size(); ++i)

       {

              cout<< students[i].name() <<string(maxlen+1-students[i].name().size(),'');

              try{

                     doublefinal_grade = students[i].grade();

                     streamsizeprec = cout.precision();

                     cout<< setprecision(3) <<final_grade <<setprecision(prec)<< endl;

              }catch(domain_error e){

                     cout<< e.what() << endl;

              }

       }

       return0;

}

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

好吧,这个程序也不能运行。。。。。。其中有些还不全面的东西。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值