文章目录
0 编译运行本章例程
0.1 对类型依赖
//
// Created by MacBook Pro on 2020-03-19.
//
#ifndef ACM_TEST_H
#define ACM_TEST_H
class Core{
public:
Core():midterm(0),final(0){}
Core(std::istream& is){read(is);}
std::string name() const;
virtual std::istream& read(std::istream&);
virtual double grade() const;
protected:
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
private:
std::string n;
};
class Grad:public Core{
public:
Grad():thesis(0){}
Grad(std::istream& is){read(is);}
double grade() const;
std::istream& read(std::istream&);
private:
double thesis;
};
std::istream& read_hw(std::istream&, std::vector<double>&);
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double median(std::vector<double> );
bool compare(const Core& , const Core& );
bool compare_core_ptrs(const Core*, const Core*);
bool compare_grades(const Core& , const Core&);
#endif //ACM_TEST_H
源文件:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <string>
#include "test.h"
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::domain_error;
using std::vector;
using std::min;
using std::string;
using std::max;
using std::streamsize;
using std::setprecision;
using std::sort;
using std::string;
std::istream& read_hw(std::istream&, std::vector<double>&);
std::string Core::name() const { return n;}
istream& Core::read_common(istream& in){
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in){
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in){
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
//不能将重载函数命名为模版参数,不然编译器无法决定调用按一个版本
bool compare(const Core& c1, const Core& c2){
return c1.name() < c2.name();
}
bool compare_grades(const Core& c1, const Core& c2){
return c1.grade() < c2.grade();
}
//改版一
bool compare_core_ptrs(const Core* cp1, const Core* cp2){
return compare(*cp1, *cp2);
}
double Core::grade() const{
return ::grade(midterm, final, homework);
}
double Grad::grade() const {
return min(Core::grade(), thesis);//显示表明
}
double median(vector<double> vec){
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
int main(int argc, char** argv){
//类型依赖(向量的定义)
vector<Core> students;
// vector<Grad> students;
Core record;
// Grad record;
string::size_type maxlen = 0;
while(record.read(cin)){
maxlen = max(maxlen, record.name().size());
students.push_back(record);
}
sort(students.begin(), students.end(), compare);
for (vector<Core>::size_type i = 0; i != students.size(); ++i) {
cout << students[i].name()
<< string(maxlen + 1 - students[i].name().size(),' ');
try{
//grade函数(类型依赖)
double final_grade = students[i].grade();
streamsize pre = cout.precision();
cout << setprecision(3) << final_grade//Core函数
<< setprecision(pre) << endl;
}catch(domain_error e){
cout << e.what() << endl;
}
}
// for (vector<Grad>::size_type i = 0; i != students.size(); ++i) {
// cout << students[i].name()
// << string(maxlen + 1 - students[i].name().size(),' ');
// try{
// //grade函数(类型依赖)
// double final_grade = students[i].grade();
// streamsize pre = cout.precision();
// cout << setprecision(3) << final_grade//Grad::grade
// << setprecision(pre) << endl;
// }catch(domain_error e){
// cout << e.what() << endl;
// }
// }
return 0;
}
0.2 摆脱类型依赖,传递指针
//
// tudent_info.h
//
#ifndef ACM_Student_info
#define ACM_Student_info
#include <iostream>
#include <string>
#include <vector>
class Core{
public:
//虚拟析构函数
//Grad在内的全部派生类会继承这个析构函数
virtual ~Core(){}
//构造函数
//默认构造函数(构造初始化器)
Core():midterm(0), final(0){}
//使用一个istream类型变量构造一个Core对象
Core(std::istream& is) {read(is);}
//存取器函数(允许对一部分数据结构访问)
std::string name() const;
virtual std::istream& read(std::istream&);
//虚拟函数(指针或引用指向的对象的实际类型在运行时是可以变化的)
//只能在类内定义
//只有以引用或指针为参数调用虚拟函数时,它们的选择才会有意义(动态绑定)
//以对象(区别于指针或引用)调用虚拟函数,在编译时候对象的类型就确定了,运行时也不会改变(静态绑定)
//通过虚拟函数+动态绑定的特性以支持多态性(多态的调用)
//多态性:一种类型可以表示几种类型(由该类派生出来的任何一个子类)
//可以用一个Core类型的指针指向一个Core类型对象或它的派生类如(Grad类型对象)
virtual double grade() const;
protected://赋予派生类访问基类中保护成员的权利
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
private://只有Core类成员以及它的友元函数可以访问
std::string n;
};
//继承:Grad类是从Core类中派生出来,
//Core类中的每个成员(除构造函数、赋值运算符和西沟函数除外)也是Grad的成员
class Grad:public Core{
public:
//构造函数
//两个构造函数均隐式地调用Core::Core()函数,以初始化对象中的基类部分
Grad():thesis(0){}
Grad(std::istream& is){ read(is); }
double grade() const;
std::istream& read(std::istream&);
private:
double thesis;
};
std::istream& read_hw(std::istream&, std::vector<double>&);
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double median(std::vector<double> );
bool compare(const Core& , const Core& );
bool compare_core_ptrs(const Core*, const Core*);
bool compare_grades(const Core& , const Core&);
#endif
主函数:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <string>
#include "Student_info.h"
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::domain_error;
using std::vector;
using std::min;
using std::string;
using std::max;
using std::streamsize;
using std::setprecision;
using std::sort;
using std::string;
std::string Core::name() const { return n;}
istream& Core::read_common(istream& in){
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in){
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in){
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
//不能将重载函数命名为模版参数,不然编译器无法决定调用按一个版本
//指向Core类型的指针,也可以将指向Grad的指针传给它,编译器会转换为Core*
bool compare(const Core& c1, const Core& c2){
return c1.name() < c2.name();
}
bool compare_core_ptrs(const Core* cp1, const Core* cp2){
return compare(*cp1, *cp2);
}
bool compare_grades(const Core& c1, const Core& c2){
return c1.grade() < c2.grade();
}
double Core::grade() const{
return ::grade(midterm, final, homework);
}
double Grad::grade() const {
return min(Core::grade(), thesis);//显示表明
}
double median(vector<double> vec){
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
int main(int argc, char** argv){
//改版一(需用户自己管理好从文件中读出数据所占的内存,检测程序正在读的记录类型)
vector<Core*> students;
Core* record;
string::size_type maxlen = 0;
//改版一(使用指针或引用)
char ch;
while(cin >> ch){
if(ch == 'U'){
record = new Core;//为一个Core类型对象分配内存
}else{
record = new Grad;//为一个Grad类型对象分配内存
}
record->read(cin);//虚拟调用
maxlen = max(maxlen, record->name().size());//间接引用
students.push_back(record);
}
//改版一(使用指针或引用)
sort(students.begin(), students.end(), compare_core_ptrs);
//改版一(使用指针或引用)
for (vector<Core*>::size_type i = 0; i != students.size(); ++i) {
cout << students[i]->name()
<< string(maxlen + 1 - students[i]->name().size(),' ');
try{
//grade函数(类型依赖)
double final_grade = students[i]->grade();
streamsize pre = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(pre) << endl;
}catch(domain_error e){
cout << e.what() << endl;
}
delete students[i];//释放在读内存时生成的临时变量
}
return 0;
}
0.3 句柄类(接口和指针类合并)
//
// Student_info.h
//
#ifndef ACM_Student_info
#define ACM_Student_info
#include <iostream>
#include <string>
#include <vector>
//#include "Handle.h"
class Core{
friend class Student_info;
public:
//虚拟析构函数
//Grad在内的全部派生类会继承这个析构函数
virtual ~Core(){}
//构造函数
//默认构造函数(构造初始化器)
Core():midterm(0), final(0){}
//使用一个istream类型变量构造一个Core对象
Core(std::istream& is) {read(is);}
//存取器函数(允许对一部分数据结构访问)
std::string name() const;
virtual std::istream& read(std::istream&);
//虚拟函数(指针或引用指向的对象的实际类型在运行时是可以变化的)
//只能在类内定义
//只有以引用或指针为参数调用虚拟函数时,它们的选择才会有意义(动态绑定)
//以对象(区别于指针或引用)调用虚拟函数,在编译时候对象的类型就确定了,运行时也不会改变(静态绑定)
//通过虚拟函数+动态绑定的特性以支持多态性(多态的调用)
//多态性:一种类型可以表示几种类型(由该类派生出来的任何一个子类)
//可以用一个Core类型的指针指向一个Core类型对象或它的派生类如(Grad类型对象)
virtual double grade() const;
protected://赋予派生类访问基类中保护成员的权利
virtual Core* clone() const{return new Core(*this);}
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
private://只有Core类成员以及它的友元函数可以访问
std::string n;
};
//继承:Grad类是从Core类中派生出来,
//Core类中的每个成员(除构造函数、赋值运算符和西沟函数除外)也是Grad的成员
class Grad:public Core{
public:
//构造函数
//两个构造函数均隐式地调用Core::Core()函数,以初始化对象中的基类部分
Grad():thesis(0){}
Grad(std::istream& is){ read(is); }
double grade() const;
std::istream& read(std::istream&);
protected:
virtual Grad* clone(){ return new Grad(*this);}
private:
double thesis;
};
std::istream& read_hw(std::istream&, std::vector<double>&);
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double median(std::vector<double> );
bool compare(const Core& , const Core& );
bool compare_core_ptrs(const Core*, const Core*);
bool compare_grades(const Core& , const Core&);
#endif
//
// Created by MacBook Pro on 2020-03-18.
//
#ifndef ACM_HANDLE_H
#define ACM_HANDLE_H
#include <iostream>
#include "Student_info.h"
class Student_info{
public:
//构造函数
Student_info ():cp(0){}
Student_info (std::istream& is):cp(0){read(is);}
//复制构造
Student_info (const Student_info&);
//赋值构造
Student_info& operator=(const Student_info&);
//析构函数
~Student_info(){delete cp;}
std::istream& read(std::istream&);
std::string name()const{
if(cp) return cp->name();
else throw std::runtime_error("uninitialized Student");
}
double grade() const {
if(cp) return cp->grade();
else throw std::runtime_error("uninitialized Student");
}
static bool compare(const Student_info& s1, const Student_info s2){
return s1.name() < s2.name();
}
private:
Core* cp;
};
std::istream& Student_info::read(std::istream& is){
delete cp;//如果有的话,删除所指对象,删除一个零指针也是无害的
char ch;
is >> ch;
if(ch == 'U') cp = new Core(is);
else cp = new Grad(is);
return is;
}
Student_info::Student_info(const Student_info& s):cp(0) {
if(s.cp) cp = s.cp->clone();
}
Student_info& Student_info::operator=(const Student_info& s) {
if(&s != this){
delete(cp);
if(s.cp){
cp = s.cp->clone();
}else{
cp = 0;
}
}
return *this;
}
#endif //ACM_HANDLE_H
源文件:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <string>
#include "Student_info.h"
#include "Handle.h"
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::domain_error;
using std::vector;
using std::min;
using std::string;
using std::max;
using std::streamsize;
using std::setprecision;
using std::sort;
using std::string;
std::string Core::name() const { return n;}
istream& Core::read_common(istream& in){
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in){
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in){
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
//不能将重载函数命名为模版参数,不然编译器无法决定调用按一个版本
//指向Core类型的指针,也可以将指向Grad的指针传给它,编译器会转换为Core*
bool compare(const Core& c1, const Core& c2){
return c1.name() < c2.name();
}
bool compare_core_ptrs(const Core* cp1, const Core* cp2){
return compare(*cp1, *cp2);
}
bool compare_grades(const Core& c1, const Core& c2){
return c1.grade() < c2.grade();
}
double Core::grade() const{
return ::grade(midterm, final, homework);
}
double Grad::grade() const {
return min(Core::grade(), thesis);//显示表明
}
double median(vector<double> vec){
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
int main(int argc, char** argv){
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
while(record.read(cin)){
maxlen = max(maxlen, record.name().size());
students.push_back(record);
}
sort(students.begin(), students.end(), Student_info::compare);
for (vector<Student_info>::size_type i = 0; i != students.size(); ++i) {
cout << students[i].name()
<< string(maxlen + 1 -students[i].name().size(), ' ');
try{
double final_grade = students[i].grade();
streamsize prec = cout.precision();
cout <<setprecision(3) << final_grade
<< setprecision(prec) << endl;
}catch (domain_error e){
cout << e.what() << endl;
}
}
return 0;
}
0.4 句柄改进(指针类和接口类分离设计)
句柄类的指针类:
#ifndef ACM_HANDLE_H
#define ACM_HANDLE_H
#include <iostream>
#include <string>
#include "Student_info.h"
template<class T> class Handle{
public:
//构造函数
Handle():p(0){}
//复制构造
Handle(const Handle& s):p(0){if(s.p) p = s.p->clone();}
//赋值运算符
Handle& operator=(const Handle&);
//使指针与实际对象关联
//例如Handle<Core> student(new Grad);
//封装了一个Cote*指针,对该指针初始化,指向生成的一个Grad类型对象
Handle(T* t):p(t){}
//析构函数
~Handle(){delete p;}
//运算符函数
//允许条件语句中检测一个Handle类型对象的值
operator bool() const { return p;}
//访问与Handle相关联的对象
//得到该指针指向的对象
//*student 等同于*(student.p) student类型对象
T& operator*() const;
//返回一个可以看作是指针的值
//student->y 等同于 (student.operator->)->y 等同于 student.p->y
//自我保护机制通常不允许我们直接访问student.p
//因此,->运算符会把对Hanle类型对象里的函数调用交给Handle类型对象的指针成员
T* operator->() const;
private:
T* p;
};
template <class T>
T& Handle<T>::operator*() const {
if(p) return *p;
throw std::runtime_error("unbound Handle ");
}
template <class T>
T* Handle<T>::operator->() const {
if(p) return p;
throw std::runtime_error("unbound Handle");
}
template <class T>
Handle<T>& Handle<T>::operator=(const Handle &rhs) {
if(&rhs != this){
delete(p);
p = rhs.p ? rhs.p->clone():0;
}
return *this;
}
class Student_info{
public:
Student_info(){}
Student_info(std::istream& is){ read(is);}
std::istream& read(std::istream&);
std::string name() const{
if(cp) return cp->name();
else throw std::runtime_error("uninitialized Student");
}
double grade() const{
if(cp) return cp->grade();
else throw std::runtime_error("uninitialized Student");
}
static bool compare(const Student_info& s1, const Student_info& s2){
return s1.name() < s2.name();
}
private:
Handle<Core> cp;
};
std::istream& Student_info::read(std::istream& is){
与之前的不同,删除了这句话,因为对cp进行赋值会释放对象暂用的内存
//Hanle类的赋值运算符函数会在赋值给cp的时候,自动删除Handle此前所指的对象
// delete cp;//如果有的话,删除所指对象,删除一个零指针也是无害的
char ch;
is >> ch;
if(ch == 'U') cp = new Core(is);
else cp = new Grad(is);
return is;
}
#endif //ACM_HANDLE_H
基类和派生类的头文件:
//
// tudent_info.h
//
#ifndef ACM_Student_info
#define ACM_Student_info
#define ANNOTATE 0
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include "Vec.h"
//#include "Handle.h"
//前置声明
template <class T> class Handle;
class Core{
friend class Student_info;
friend class Audit;
friend class Handle<Core>;
public:
//虚拟析构函数
//Grad在内的全部派生类会继承这个析构函数
virtual ~Core(){}
//构造函数
//默认构造函数(构造初始化器)
Core():midterm(0), final(0){
#if ANNOTATE == 1
std::cerr<<"Core::Core()"<<std::endl;
#endif
}
//使用一个istream类型变量构造一个Core对象
Core(std::istream& is) {
#if ANNOTATE == 1
std::cerr<<"Core::Core(istream&)"<<std::endl;
#endif
read(is);
}
//存取器函数(允许对一部分数据结构访问)
std::string name() const;
virtual std::istream& read(std::istream&);
//虚拟函数(指针或引用指向的对象的实际类型在运行时是可以变化的)
//只能在类内定义
//只有以引用或指针为参数调用虚拟函数时,它们的选择才会有意义(动态绑定)
//以对象(区别于指针或引用)调用虚拟函数,在编译时候对象的类型就确定了,运行时也不会改变(静态绑定)
//通过虚拟函数+动态绑定的特性以支持多态性(多态的调用)
//多态性:一种类型可以表示几种类型(由该类派生出来的任何一个子类)
//可以用一个Core类型的指针指向一个Core类型对象或它的派生类如(Grad类型对象)
virtual double grade() const;
//改成绩
void regrade(double d){final = d;}
virtual void regrade(double d, double = 0){final = d;}
//检查是否做了homework是否为空
bool valid() const{ return ! homework.empty();}
//转换成字母
std::string letter_grade() const;
//检测是否完成了作业
virtual bool requirements_met() const{
return std::find(homework.begin(),homework.end(),0.0) == homework.end();
}
protected://赋予派生类访问基类中保护成员的权利
virtual Core* clone() const{return new Core(*this);}
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
private://只有Core类成员以及它的友元函数可以访问
std::string n;
};
//继承:Grad类是从Core类中派生出来,
//Core类中的每个成员(除构造函数、赋值运算符和西沟函数除外)也是Grad的成员
class Grad:public Core{
public:
//构造函数
//两个构造函数均隐式地调用Core::Core()函数,以初始化对象中的基类部分
Grad():thesis(0){
#if ANNOTATE == 1
std::cerr<<"Grad::Grad()"<<std::endl;
#endif
}
Grad(std::istream& is){
#if ANNOTATE == 1
std::cerr<<"Grad::Grad(istream&)"<<std::endl;
#endif
read(is); }
//读入信息
std::istream& read(std::istream&);
//计算成绩
double grade() const;
//修改成绩
void regrade(double d1, double d2){final = d1; thesis = d2;}
//检查有没有写出一篇论文
bool requirements_met() const{
return Core::requirements_met() && (thesis != 0);
}
protected:
Grad* clone(){ return new Grad(*this);}
private:
double thesis;
};
class Credit: public Core{
public:
Credit():Core(){}
Credit(std::istream& is):Core(is){}
double grade() const;
bool passed ()const{ return grade() >= 60; }
protected:
Credit* clone() const { return new Credit(*this);}
};
class Audit:public Core{
public:
typedef std::map<std::string, double> mp;
typedef std::map<std::string, double>::const_iterator const_iterator;
typedef std::map<std::string, double>::iterator iterator;
Audit():maxlen(0){}
Audit(std::istream& is){ read(is);}
std::istream& read(std::istream&);
void print_checked(const std::string& name) const{
if(checked(name) != -1){
std::cout <<checked(name) << std::endl;
}else{
std::cout << "Without this student!"<<std::endl;
}
}
void print_chart() const{
if(students_garde.size() != 0){
for (const_iterator iter = students_garde.begin(); iter != students_garde.end(); ++iter) {
std::cout<< iter->first << std::string(maxlen + 1 - iter->first.size(),' ')
<< std::string(iter->second/5, '=') << std::endl;
}
}
}
protected:
Audit* clone() const{ return new Audit(*this);}
double checked(const std::string&) const;
private:
mp students_garde;
std::string::size_type maxlen;
};
std::istream& read_hw(std::istream&, std::vector<double>&);
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double median(std::vector<double> );
bool compare(const Core& , const Core& );
bool compare_core_ptrs(const Core*, const Core*);
bool compare_grades(const Core& , const Core&);
#endif
源代码:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <string>
#include "Student_info.h"
#include "Handle.h"
#include <fstream>
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::domain_error;
using std::vector;
using std::min;
using std::string;
using std::max;
using std::streamsize;
using std::setprecision;
using std::sort;
using std::string;
std::string Core::name() const {
#if ANNOTATE == 1
std::cerr<<" Core::name() "<<std::endl;
#endif
return n;}
istream& Core::read_common(istream& in){
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in){
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in){
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
//不能将重载函数命名为模版参数,不然编译器无法决定调用按一个版本
//指向Core类型的指针,也可以将指向Grad的指针传给它,编译器会转换为Core*
bool compare(const Core& c1, const Core& c2){
return c1.name() < c2.name();
}
bool compare_core_ptrs(const Core* cp1, const Core* cp2){
return compare(*cp1, *cp2);
}
bool compare_grades(const Core& c1, const Core& c2){
return c1.grade() < c2.grade();
}
double Core::grade() const{
#if ANNOTATE == 1
std::cerr<<" Core::grade()"<<std::endl;
#endif
return ::grade(midterm, final, homework);
}
double Grad::grade() const {
#if ANNOTATE == 1
std::cerr<<" Grad::grade()"<<std::endl;
#endif
return min(Core::grade(), thesis);//显示表明
}
double median(vector<double> vec){
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
string Core::letter_grade() const {
static const double numbers[]={
97, 94, 90, 87, 84, 80, 77, 74, 70, 60, 0
};
static const char* const letters[]={
"A+","A","A-","B+","B","B-","C+","C","C-","D","F"
};
//计算成绩的个数
static const size_t ngrades = sizeof(numbers)/sizeof(*numbers);
double result = grade();
for (size_t i = 0; i < ngrades; ++i) {
if(result >= numbers[i]){
return letters[i];
}
}
return "? \? \?";
}
double Credit::grade() const {
if(homework.empty()){
return (midterm + final)/2;
}else{
return Core::grade();
}
}
istream& Audit::read(std::istream &is) {
Core* record;
char ch;
maxlen = 0;
while(is >> ch) {
if (ch == 'U') {
record = new Core;//为一个Core类型对象分配内存
} else{
record = new Grad;//为一个Grad类型对象分配内存
}
record->read(is);//虚拟调用
maxlen = max(maxlen, record->name().size());
students_garde[record->name()] = record->grade();
}
return is;
}
double Audit::checked(const std::string & name) const {
const_iterator iter = students_garde.find(name);
if(iter != students_garde.end()){
return iter->second;
}else{
return -1;
}
}
//重写比较函数bool compare_Core_handles(const Handle<Core> cp1, const Handle<Core> cp2){
return compare(*cp1, *cp2);
}
int main(int argc, char** argv){
vector<Handle<Core>> students;
Handle<Core> record;
char ch;
string::size_type maxlen = 0;
while(cin >> ch){
if(ch == 'U'){
record = new Core;
}else{
record = new Grad;
}
record->read(cin);
maxlen = max(maxlen, record->name().size());
students.push_back(record);
}
sort(students.begin(), students.end(), compare_Core_handles);
for (vector<Handle<Core>>::size_type i = 0; i != students.size(); ++i) {
cout << students[i]->name()
<< string(maxlen + 1 - students[i]->name().size(),' ');
try{
double final_grade = students[i]->grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
}catch(domain_error e){
cout << e.what() <<endl;
}
}
return 0;
}
0.5 引用计数句柄
//
// Created by MacBook Pro on 2020-03-18.
//
#ifndef ACM_HANDLE_H
#define ACM_HANDLE_H
#include <iostream>
#include <string>
#include "Student_info.h"
//class Student_info{
//public:
// //构造函数
// Student_info ():cp(0){}
// Student_info (std::istream& is):cp(0){read(is);}
// //复制构造
// Student_info (const Student_info&);
// //赋值构造
// Student_info& operator=(const Student_info&);
// //析构函数
// ~Student_info(){delete cp;}
//
// std::istream& read(std::istream&);
//
// std::string name()const{
// if(cp) return cp->name();
// else throw std::runtime_error("uninitialized Student");
// }
// double grade() const {
// if(cp) return cp->grade();
// else throw std::runtime_error("uninitialized Student");
// }
// static bool compare(const Student_info& s1, const Student_info s2){
// return s1.name() < s2.name();
// }
//
// void regrade(double d1, double d2 = 0){
// if(cp) return cp->regrade(d1, d2);
// else throw std::runtime_error("uninitialized Student");
// }
//
// bool valid() const{
// if(cp) return cp->valid();
// else throw std::runtime_error("uninitialized Student");
// }
//
// std::string letter_grade() const{
// if(cp) return cp->letter_grade();
// else throw std::runtime_error("uninitialized Student");
// }
//
// bool requirement_met() const{
// if(cp) return cp->requirements_met();
// else throw std::runtime_error("uninitialized Student");
// }
//
//
//private:
// Core* cp;
//};
//std::istream& Student_info::read(std::istream& is){
// delete cp;//如果有的话,删除所指对象,删除一个零指针也是无害的
//
// char ch;
// is >> ch;
// if(ch == 'U') cp = new Core(is);
// else cp = new Grad(is);
// return is;
//}
//Student_info::Student_info(const Student_info& s):cp(0) {
// if(s.cp) cp = s.cp->clone();
//}
//Student_info& Student_info::operator=(const Student_info& s) {
// if(&s != this){
// delete(cp);
// if(s.cp){
// cp = s.cp->clone();
// }else{
// cp = 0;
// }
// }
// return *this;
//}
template<class T> class Handle{
public:
//构造函数
Handle():p(0){}
//复制构造
Handle(const Handle& s):p(0){if(s.p) p = s.p->clone();}
//赋值运算符
Handle& operator=(const Handle&);
//使指针与实际对象关联
//例如Handle<Core> student(new Grad);
//封装了一个Cote*指针,对该指针初始化,指向生成的一个Grad类型对象
Handle(T* t):p(t){}
//析构函数
~Handle(){delete p;}
//运算符函数
//允许条件语句中检测一个Handle类型对象的值
operator bool() const { return p;}
//访问与Handle相关联的对象
//得到该指针指向的对象
//*student 等同于*(student.p) student类型对象
T& operator*() const;
//返回一个可以看作是指针的值
//student->y 等同于 (student.operator->)->y 等同于 student.p->y
//自我保护机制通常不允许我们直接访问student.p
//因此,->运算符会把对Hanle类型对象里的函数调用交给Handle类型对象的指针成员
T* operator->() const;
private:
T* p;
};
template <class T>
T& Handle<T>::operator*() const {
if(p) return *p;
throw std::runtime_error("unbound Handle ");
}
template <class T>
T* Handle<T>::operator->() const {
if(p) return p;
throw std::runtime_error("unbound Handle");
}
template <class T>
Handle<T>& Handle<T>::operator=(const Handle &rhs) {
if(&rhs != this){
delete(p);
p = rhs.p ? rhs.p->clone():0;
}
return *this;
}
template <class T> class Ref_handle{
public:
//构造函数
Ref_handle():p(0),refptr(new std::size_t(1)){}
//使指针与实际对象关联
Ref_handle(T* t):p(t), refptr(new std::size_t(1)){}
//进行复制时加1
Ref_handle(const Ref_handle& h):p(h.p), refptr(h.refptr){
++*refptr;
}
//赋值运算符函数
Ref_handle& operator=(const Ref_handle&);
//析构函数
~Ref_handle();
operator bool()const { return p;}
T& operator*() const{
if(p) return *p;
throw std::runtime_error("unbound Ref_handle");
}
T* operator->() const{
if(p) return p;
throw std::runtime_error("unbound Ref_handle");
};
private:
T* p;
std::size_t* refptr;
};
template <class T>
Ref_handle<T>& Ref_handle<T>::operator=(const Ref_handle &rhs) {
//取保引用计数不会被无意义归零
++*rhs.refptr;
//释放做操作数对象,如有必要释放指针
if(--*refptr == 0){//防止自我赋值
delete(refptr);
delete(p);
}
//赋值右操作数对象的值
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template <class T>
Ref_handle<T>::~Ref_handle() {
if(--*refptr == 0){
delete(refptr);
delete(p);
}
}
template <class T>T* clone(const T* tp){
return tp->clone();
}
template <class T>
class Ptr{
public:
//在需要时有条件复制对象
void make_unique(){
if(*refptr != 1){
--*refptr;
refptr = new size_t(1);
p = p?clone(p):0;
}
}
Ptr():p(0),refptr(new size_t(1)){}
Ptr(T* t):p(t),refptr(new size_t(1)){}
Ptr(const Ptr& h):p(h.p),refptr(h.refptr){++*refptr;}
Ptr& operator=(const Ptr&);
~Ptr();
operator bool() const {return p;}
T& operator*() const{
if(p) return *p;
throw std::runtime_error("unbound Ptr");
}
T* operator->() const{
if(p) return p;
throw std::runtime_error("unbound Ptr");
}
private:
T* p;
std::size_t * refptr;
};
template <class T>
Ptr<T>& Ptr<T>::operator=(const Ptr &rhs) {
++*rhs.refptr;
if(--*refptr == 0){
delete(refptr);
delete(p);
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template <class T>
Ptr<T>::~Ptr() {
if(--*refptr==0){
delete(refptr);
delete(p);
}
}
//重写Student_info的代码
class Student_info{
public:
Student_info(){}
Student_info(std::istream& is){ read(is);}
std::istream& read(std::istream&);
std::string name() const{
if(cp) return cp->name();
else throw std::runtime_error("uninitialized Student");
}
double grade() const{
if(cp) return cp->grade();
else throw std::runtime_error("uninitialized Student");
}
static bool compare(const Student_info& s1, const Student_info& s2){
return s1.name() < s2.name();
}
void regrade(double final, double thesis){
//改变时,先得到副本
cp.make_unique();
if(cp) cp->regrade(final, thesis);
else throw std::runtime_error("regrade of unknown students");
}
private:
// Handle<Core> cp;
Ptr<Core> cp;
};
std::istream& Student_info::read(std::istream& is){
与之前的不同,删除了这句话,因为对cp进行赋值会释放对象暂用的内存
//Hanle类的赋值运算符函数会在赋值给cp的时候,自动删除Handle此前所指的对象
// delete cp;//如果有的话,删除所指对象,删除一个零指针也是无害的
char ch;
is >> ch;
if(ch == 'U') cp = new Core(is);
else cp = new Grad(is);
return is;
}
#endif //ACM_HANDLE_H
基类及派生类头文件:
//
// tudent_info.h
//
#ifndef ACM_Student_info
#define ACM_Student_info
#define ANNOTATE 0
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
//#include "Handle.h"
//前置声明
template <class T> class Handle;
template <class T> class Ptr;
template <class T>T* clone(const T*);
class Core{
friend class Student_info;
friend class Audit;
friend class Handle<Core>;
friend class Ptr<Core>;
friend Core* clone(const Core*);
public:
//虚拟析构函数
//Grad在内的全部派生类会继承这个析构函数
virtual ~Core(){}
//构造函数
//默认构造函数(构造初始化器)
Core():midterm(0), final(0){
#if ANNOTATE == 1
std::cerr<<"Core::Core()"<<std::endl;
#endif
}
//使用一个istream类型变量构造一个Core对象
Core(std::istream& is) {
#if ANNOTATE == 1
std::cerr<<"Core::Core(istream&)"<<std::endl;
#endif
read(is);
}
//存取器函数(允许对一部分数据结构访问)
std::string name() const;
virtual std::istream& read(std::istream&);
//虚拟函数(指针或引用指向的对象的实际类型在运行时是可以变化的)
//只能在类内定义
//只有以引用或指针为参数调用虚拟函数时,它们的选择才会有意义(动态绑定)
//以对象(区别于指针或引用)调用虚拟函数,在编译时候对象的类型就确定了,运行时也不会改变(静态绑定)
//通过虚拟函数+动态绑定的特性以支持多态性(多态的调用)
//多态性:一种类型可以表示几种类型(由该类派生出来的任何一个子类)
//可以用一个Core类型的指针指向一个Core类型对象或它的派生类如(Grad类型对象)
virtual double grade() const;
//改成绩
void regrade(double d){final = d;}
virtual void regrade(double d, double = 0){final = d;}
//检查是否做了homework是否为空
bool valid() const{ return ! homework.empty();}
//转换成字母
std::string letter_grade() const;
//检测是否完成了作业
virtual bool requirements_met() const{
return std::find(homework.begin(),homework.end(),0.0) == homework.end();
}
protected://赋予派生类访问基类中保护成员的权利
virtual Core* clone() const{return new Core(*this);}
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
private://只有Core类成员以及它的友元函数可以访问
std::string n;
};
//继承:Grad类是从Core类中派生出来,
//Core类中的每个成员(除构造函数、赋值运算符和西沟函数除外)也是Grad的成员
class Grad:public Core{
public:
//构造函数
//两个构造函数均隐式地调用Core::Core()函数,以初始化对象中的基类部分
Grad():thesis(0){
#if ANNOTATE == 1
std::cerr<<"Grad::Grad()"<<std::endl;
#endif
}
Grad(std::istream& is){
#if ANNOTATE == 1
std::cerr<<"Grad::Grad(istream&)"<<std::endl;
#endif
read(is); }
//读入信息
std::istream& read(std::istream&);
//计算成绩
double grade() const;
//修改成绩
void regrade(double d1, double d2){final = d1; thesis = d2;}
//检查有没有写出一篇论文
bool requirements_met() const{
return Core::requirements_met() && (thesis != 0);
}
protected:
Grad* clone(){ return new Grad(*this);}
private:
double thesis;
};
class Credit: public Core{
public:
Credit():Core(){}
Credit(std::istream& is):Core(is){}
double grade() const;
bool passed ()const{ return grade() >= 60; }
protected:
Credit* clone() const { return new Credit(*this);}
};
class Audit:public Core{
public:
typedef std::map<std::string, double> mp;
typedef std::map<std::string, double>::const_iterator const_iterator;
typedef std::map<std::string, double>::iterator iterator;
Audit():maxlen(0){}
Audit(std::istream& is){ read(is);}
std::istream& read(std::istream&);
void print_checked(const std::string& name) const{
if(checked(name) != -1){
std::cout <<checked(name) << std::endl;
}else{
std::cout << "Without this student!"<<std::endl;
}
}
void print_chart() const{
if(students_garde.size() != 0){
for (const_iterator iter = students_garde.begin(); iter != students_garde.end(); ++iter) {
std::cout<< iter->first << std::string(maxlen + 1 - iter->first.size(),' ')
<< std::string(iter->second/5, '=') << std::endl;
}
}
}
protected:
Audit* clone() const{ return new Audit(*this);}
double checked(const std::string&) const;
private:
mp students_garde;
std::string::size_type maxlen;
};
std::istream& read_hw(std::istream&, std::vector<double>&);
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double median(std::vector<double> );
bool compare(const Core& , const Core& );
bool compare_core_ptrs(const Core*, const Core*);
bool compare_grades(const Core& , const Core&);
#endif
源代码:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <string>
#include "Student_info.h"
#include "Handle.h"
#include <fstream>
#include <sstream>
using std::stringstream;
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::domain_error;
using std::vector;
using std::min;
using std::string;
using std::max;
using std::streamsize;
using std::setprecision;
using std::sort;
using std::string;
std::string Core::name() const {
#if ANNOTATE == 1
std::cerr<<" Core::name() "<<std::endl;
#endif
return n;}
istream& Core::read_common(istream& in){
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in){
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in){
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
//不能将重载函数命名为模版参数,不然编译器无法决定调用按一个版本
//指向Core类型的指针,也可以将指向Grad的指针传给它,编译器会转换为Core*
bool compare(const Core& c1, const Core& c2){
return c1.name() < c2.name();
}
//Handle类调用
bool compare_Core_handles(const Handle<Core> cp1, const Handle<Core> cp2){
return compare(*cp1, *cp2);
}
bool compare_Core_Ptr(const Ptr<Core> cp1, const Ptr<Core> cp2){
return compare(*cp1, *cp2);
}
bool compare_grades(const Core& c1, const Core& c2){
return c1.grade() < c2.grade();
}
double Core::grade() const{
#if ANNOTATE == 1
std::cerr<<" Core::grade()"<<std::endl;
#endif
return ::grade(midterm, final, homework);
}
double Grad::grade() const {
#if ANNOTATE == 1
std::cerr<<" Grad::grade()"<<std::endl;
#endif
return min(Core::grade(), thesis);//显示表明
}
double median(vector<double> vec){
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
string Core::letter_grade() const {
static const double numbers[]={
97, 94, 90, 87, 84, 80, 77, 74, 70, 60, 0
};
static const char* const letters[]={
"A+","A","A-","B+","B","B-","C+","C","C-","D","F"
};
//计算成绩的个数
static const size_t ngrades = sizeof(numbers)/sizeof(*numbers);
double result = grade();
for (size_t i = 0; i < ngrades; ++i) {
if(result >= numbers[i]){
return letters[i];
}
}
return "? \? \?";
}
double Credit::grade() const {
if(homework.empty()){
return (midterm + final)/2;
}else{
return Core::grade();
}
}
istream& Audit::read(std::istream &is) {
Core* record;
char ch;
maxlen = 0;
while(is >> ch) {
if (ch == 'U') {
record = new Core;//为一个Core类型对象分配内存
} else{
record = new Grad;//为一个Grad类型对象分配内存
}
record->read(is);//虚拟调用
maxlen = max(maxlen, record->name().size());
students_garde[record->name()] = record->grade();
}
return is;
}
double Audit::checked(const std::string & name) const {
const_iterator iter = students_garde.find(name);
if(iter != students_garde.end()){
return iter->second;
}else{
return -1;
}
}
int main(int argc, char** argv){
vector<Student_info> students;
Student_info record;
char ch;
string::size_type maxlen = 0;
std::ifstream infile("/Users/macbookpro/CLionProjects/ACM/students10.txt");
while(record.read(infile)){
maxlen = max(maxlen, record.name().size());
students.push_back(record);
}
infile.close();
infile.clear();
sort(students.begin(), students.end(), Student_info::compare);
for (vector<Student_info>::size_type i = 0; i != students.size(); ++i) {
cout << students[i].name()
<< string(maxlen + 1 - students[i].name().size(),' ');
try{
double final_grade = students[i].grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
}catch(domain_error e){
cout << e.what() <<endl;
}
}
return 0;
}
1 实现Ptr <Core>类的对比操作函数
bool compare_Core_Ptr(const Ptr<Core> cp1, const Ptr<Core> cp2){
return compare(*cp1, *cp2);
}
头文件同问题0.5
测试程序:
除main函数,其余同问题0.5
stringstream ss1("Jan 15 20 30 40");
stringstream ss2("Jan 80 90 70 50");
Ptr<Core> p1 = new Core(ss1);
Ptr<Core> p2 = new Core(ss2);
cout << "Is " << p1->name() << " == " << p2->name() << " ? " << (compare_Core_Ptr(p1, p2) == 0) << endl;
2 使用Ptr<Core>对象实现学生成绩程序进行检验
除源程序中的main函数,其余(头文件、源文件)同问题0.5
int main(int argc, char** argv){
vector< Ptr<Core> > students; // changed type
Ptr<Core> record; // changed type
char ch;
string::size_type maxlen = 0;
std::ifstream infile("/Users/macbookpro/CLionProjects/ACM/students10.txt");
// read and store the data
while (infile >> ch) {
if (ch == 'U')
record = new Core; // allocate a Core object
else
record = new Grad; // allocate a Grad object
record->read(infile); // Handle<T>::->, then virtual call to read
maxlen = max(maxlen, record->name().size()); // Handle<T>::->
students.push_back(record);
}
infile.close();
infile.clear();
// compare must be rewritten to work on const Handle<Core>&
sort(students.begin(), students.end(), compare_Core_Ptr);
// write the names and grades
for (vector< Ptr<Core> >::size_type i = 0;
i != students.size(); ++i) {
// students[i] is a Handle, which we dereference to call the functions
cout << students[i]->name()
<< string(maxlen + 1 - students[i]->name().size(), ' ');
try {
double final_grade = students[i]->grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
}
catch (domain_error e) {
cout << e.what() << endl;
}
// no delete statement
}
return 0;
}
3 使用Ptr类的最终版本实现Student_info类,然后用这个版本的Student_info类实现13.5节的学生成绩程序
程序同问题0.5
4 使用Ptr类重写Str类
Str类
#ifndef ACM_STR_H
#define ACM_STR_H
#include "Vec.h"
#include <iostream>
#include "Ptr.h"
//模版特化
template<>
inline Vec<char>* clone(const Vec<char>* vp)
{
return new Vec<char>(*vp);
}
class Str{
friend std::istream& operator>>(std::istream&, Str&);
public:
typedef Vec<char>::size_type size_type;
typedef Vec<char>::iterator iterator;
typedef Vec<char>::const_iterator const_iterator;
实现+=运算符(重写)
Str& operator += (const Str& s){
data.make_unique();//新增
std::copy (s.data->begin(), s.data->end(), std::back_inserter(*data));
return *this;
}
默认构造(//全部重写)
Str():data(new Vec<char>){}
//生成一个Str对象,包含c的n个副本
Str(size_type n, char c):data(new Vec<char>(n,c)){}//使用Vec类中的构造函数构造data数据
//生成一个Str对象并使用一个空字符结尾的字符数组来初始化
Str(const char* cp):data(new Vec<char>){
std::copy(cp, cp + std::strlen(cp), std::back_inserter(*data));
}
//生成一个Str对象并使用迭代器b和e之间的内容对他进行初始化
template<class In>Str (In b, In e):data(new Vec<char>){
std::copy(b, e, std::back_inserter(*data));
}
//大小
size_type size() const { return data->size();}
索引(重写)
char& operator[](size_type i) {
data.make_unique();
return (*data)[i];
}
const char &operator[](size_type i) const { return (*data)[i];}
iterator begin() { return data->begin(); };
const_iterator begin() const { return data->begin(); };
iterator end() { return data->end(); };
const_iterator end() const { return data->end(); };
private:
重写
Ptr<Vec<char> > data;//存储指向向量的指针
};
//输入运算符
std::istream& operator>>(std::istream&, Str&);
//输出运算符
std::ostream& operator<<(std::ostream&, const Str&);
//加号运算符
Str operator+(const Str&, const Str&);
//输出运算符定义
std::ostream& operator<<(std::ostream& os, const Str& s){
for (Str::size_type i = 0; i != s.size(); ++i) {
os << s[i];
}
return os;
}
//输入运算符的定义
std::istream& operator>>(std::istream& is, Str& s){
//抹去存在的值(s)
s.data->clear();
//按序读字符并忽略前面的空格字符
char c;
//值进行循环条件,不进行其他工作
while(is.get(c) && isspace(c));
//读入非空白字符
if(is){
do{
s.data->push_back(c);
}while(is.get(c) && !isspace(c));
//如果遇到一空格字符,将它放在输入流的后面
if(is){
is.unget();
}
}
return is;
}
//加号运算符的定义
Str operator+ (const Str& s, const Str& t){
Str r = s;
r += t;
return r;
}
//class Str{
// friend std::istream& operator>>(std::istream&, Str&);
//
//public:
// typedef Vec<char>::size_type size_type;
//
// //实现+=运算符
// Str& operator += (const Str& s){
// std::copy (s.data.begin(), s.data.end(), std::back_inserter(data));
// return *this;
// }
//
// //默认构造
// Str(){}
// //生成一个Str对象,包含c的n个副本
// Str(size_type n, char c):data(n,c){}//使用Vec类中的构造函数构造data数据
// //生成一个Str对象并使用一个空字符结尾的字符数组来初始化
// Str(const char* cp){
// std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
// }
// //生成一个Str对象并使用迭代器b和e之间的内容对他进行初始化
// template<class In>Str (In b, In e){
// std::copy(b, e, std::back_inserter(data));
// }
//
// //大小
// size_type size() const { return data.size();}
//
// //索引
// char& operator[](size_type i) { return data[i];}
// const char &operator[](size_type i) const { return data[i];}
//
//
//private:
// Vec<char> data;
//
//};
输入运算符
//std::istream& operator>>(std::istream&, Str&);
输出运算符
//std::ostream& operator<<(std::ostream&, const Str&);
加号运算符
//Str operator+(const Str&, const Str&);
//
输出运算符定义
//std::ostream& operator<<(std::ostream& os, const Str& s){
// for (Str::size_type i = 0; i != s.size(); ++i) {
// os << s[i];
// }
// return os;
//}
输入运算符的定义
//std::istream& operator>>(std::istream& is, Str& s){
// //抹去存在的值(s)
// s.data.clear();
// //按序读字符并忽略前面的空格字符
// char c;
// //值进行循环条件,不进行其他工作
// while(is.get(c) && isspace(c));
// //读入非空白字符
// if(is){
// do{
// s.data.push_back(c);
// }while(is.get(c) && !isspace(c));
// //如果遇到一空格字符,将它放在输入流的后面
// if(is){
// is.unget();
// }
// }
// return is;
//}
//
加号运算符的定义
//Str operator+ (const Str& s, const Str& t){
// Str r = s;
// r += t;
// return r;
//}
#endif //ACM_STR_H
Vec头文件:
#ifndef Vec_H
#define Vec_H
#include <iostream>
#include <cstddef>
#include <memory>
#include <algorithm>
template<class T> class Vec{
public:
typedef T* iterator;
typedef const T* const_iterator;//迭代器
typedef size_t size_type;//容器长度
typedef T value_type;//值类型
typedef std::ptrdiff_t difference_type;//迭代器相减后的结果
typedef T& reference;//
typedef const T& const_reference;
//构造函数
Vec(){create();}
//可以显示的给val值,也可以使用T的默认构造函数来生成这个值
explicit Vec(std::size_t n, const T& val = T()){create(n, val);}
//复制构造函数
Vec(const Vec& v) { create(v.begin(), v.end());}
//带两个迭代器参数的构造函数
template <class In> Vec(In b, In e){create(b, e);}
//赋值运算符
Vec& operator=(const Vec&);//允许忽略具体类型的名称(因此没有显示声明返回类型名称)
//析构函数
~Vec(){ uncreate();}
//索引(返回引用,是为了避免容器的对象非常大时对它进行复制)
T& operator[](size_type i) { return data[i];}//读写
const T& operator[](size_type i) const { return data[i];}//只读
//动态增加数组
void push_back(const T& t){
if(avail == limit){
grow();
}
unchecked_append(t);
}
//清空
void clear(){
destory();
}
//删除
void erase(iterator pos){
destory(pos);
}
void erase(iterator b , iterator e){
destory(b, e);
}
//出元素
void pop_back(){
pop();
}
//打印数组
std::ostream& print_vec(std::ostream&);
//判断空
bool empty() const{return !data;}
//添加元素:
void insert(iterator it,const T& t){
std::ptrdiff_t dis = it - data;
if(avail == limit) grow();
add(dis, t);
}
template <class In>
void insert(iterator out, In b, In e){
std::ptrdiff_t start = out - data;//插入位置
std::ptrdiff_t dis = e - b;
if(dis > 0){//插入区间合法
const size_type new_length = size() + size_type (dis);
size_type container = limit - data;
while(new_length >= container){
grow();
container = limit - data;
}
add(start, b, e);
}
}
template <class In>
void assign(In, In);
//容器有元素的长度
size_type size() const { return avail - data;}
//返回迭代器类型
iterator begin(){ return data;}//读写
const_iterator begin() const { return data;}//只读
iterator end() { return avail;}
const_iterator end() const { return avail;}
private:
iterator data;//指针指向Vec的第一个元素
iterator avail;//指针指向构造元素后面的一个元素
iterator limit;//指针指向最后一个可获得元素后面的一个元素
//内存分配工具
std::allocator<T> alloc;//控制内存块分配的对象
//为底层的数组分配空间并对它进行初始化
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);
template <class In> void create(In, In);
//删除数组中的元素并释放其占有的内存
void uncreate();
//支持push_back函数
void grow();
void unchecked_append(const T&);
//支持clear函数
void destory();
//支持erase函数
iterator destory(iterator);
iterator destory(iterator, iterator);
//支持pop_back
void pop();
//支持insert
void add(std::ptrdiff_t,const T&);
void add(std::ptrdiff_t, const_iterator, const_iterator);
};
//赋值运算符
template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs){
if(&rhs != this){//this:指向操作数对象的指针
//删除运算符左侧的数组
uncreate();
//从右侧复制元素到左侧
create(rhs.begin(), rhs.end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
return *this;//返回指向的对象
}
//默认构造
template<class T> void Vec<T>::create() {
data = avail = limit = 0;
}
//带一个参数大小和给初值
template<class T> void Vec<T>::create(size_type n, const T& val){
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}
//带参数大小
template<class T> void Vec<T>::create(const_iterator i, const_iterator j){
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}
template <class T>
template <class In>
void Vec<T>::create(In b, In e) {
data = alloc.allocate(e - b);
limit = avail = std::uninitialized_copy(b, e, data);
}
//删除对象,释放占用的内存
template<class T> void Vec<T>::uncreate(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
if(data){
//以相反顺序构造函数生成的元素
iterator it = avail;
while(it != data){//删除对象
alloc.destroy(--it);
}
//返回占用的所有内存空间
alloc.deallocate(data, limit - data);//删除未初始化内存
}
//重置指针以表明Vec类型对象为空
data = limit = avail = 0;
}
//push_back函数的成员函数
template<class T> void Vec<T>::grow(){
size_type new_size;
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
//Vec为空的时候,选择一个元素进行分配
new_size = std::max(2 * (limit - data), std::ptrdiff_t(1));
//分配新的内存空间并将已存在的对象元素内容复制搭配新内存中
iterator new_data = alloc.allocate(new_size);
iterator new_avail = std::uninitialized_copy(data, avail, new_data);
//返回原来的内存空间
uncreate();
//重置指针,使其指向新分配的内存空间
data = new_data;
avail = new_avail;
limit = data + new_size;
}
//假设avail指向一片新分配的但尚未初始化的内存空间
template<class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}
template <class T>
void Vec<T>::destory() {
iterator it = avail;
while(it != data){
alloc.destroy(--it);
}
avail = data;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec::iterator pos) {
if(data && pos < avail && pos >= data){
alloc.destroy(pos);
iterator it = pos +1;
while(it != avail){
alloc.construct(pos++, *it++);
alloc.destroy(pos);
}
avail = pos;
}
return avail;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec<T>::iterator b, Vec<T>::iterator e) {
if(data && b < e && e < avail && b >= data){
iterator it = b;
while(it != e){
alloc.destroy(it++);
}
while(e != avail){
alloc.construct(b++, *e);
alloc.destroy(e++);
}
avail = b;
}
return avail;
}
template<class T>
std::ostream& Vec<T>::print_vec(std::ostream &os) {
if(avail - data > 0){
const_iterator iter = data;
os << *iter++;
while(iter != avail){
os << " " << *iter++;
}
os << std::endl;
}
return os;
}
template <class T>
void Vec<T>::pop() {
if(data){
alloc.destroy(--avail);
}
}
template <class T>
void Vec<T>::add(std::ptrdiff_t dis, const T& val){
if(dis < avail - data){
iterator e = avail;
iterator b = avail -1;
while(e != data + dis){
alloc.construct(e--, *b--);
alloc.destroy(b);
}
alloc.construct(data + dis, val);
++avail;
}
}
template <class T>
void Vec<T>::add(std::ptrdiff_t start,Vec<T>::const_iterator b, Vec<T>::const_iterator e) {
iterator pos = data + size_type(start);
if(size_type(start)> size()) throw std::domain_error("");
Vec<T>temp;
iterator insert_pos = pos;
for ( ; insert_pos != avail; ++insert_pos) {//原插入位置的后面部分暂存
temp.push_back(*insert_pos);
}
for (const_iterator it = b; it != e; ++it) {//覆盖插入元素
*insert_pos++ = *it;
}
for (const_iterator it = temp.begin(); it != temp.end(); ++it) {//把愿插入位置后面的部分重新插入
*insert_pos++ = *it;
}
//更新avail
avail = insert_pos;
// std::copy(pos, avail, temp);
// std::copy(temp.begin(),temp.end(),std::copy(b, e, pos));
}
template <class T>
template <class In>
void Vec<T>::assign(In b, In e) {
uncreate();
create(b, e);
}
#endif
Ptr头文件:
//
// Created by MacBook Pro on 2020-03-20.
//
#ifndef ACM_PTR_H
#define ACM_PTR_H
template <class T>T* clone(const T* tp){
return tp->clone();
}
template <class T>
class Ptr{
public:
//在需要时有条件复制对象
void make_unique(){
if(*refptr != 1){
--*refptr;
refptr = new size_t(1);
p = p?clone(p):0;
}
}
Ptr():p(0),refptr(new size_t(1)){}
Ptr(T* t):p(t),refptr(new size_t(1)){}
Ptr(const Ptr& h):p(h.p),refptr(h.refptr){++*refptr;}
Ptr& operator=(const Ptr&);
~Ptr();
operator bool() const {return p;}
T& operator*() const{
if(p) return *p;
throw std::runtime_error("unbound Ptr");
}
T* operator->() const{
if(p) return p;
throw std::runtime_error("unbound Ptr");
}
private:
T* p;
std::size_t * refptr;
};
template <class T>
Ptr<T>& Ptr<T>::operator=(const Ptr &rhs) {
++*rhs.refptr;
if(--*refptr == 0){
delete(refptr);
delete(p);
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template <class T>
Ptr<T>::~Ptr() {
if(--*refptr==0){
delete(refptr);
delete(p);
}
}
#endif //ACM_PTR_H
测试源程序:
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include "Str.h"
int main()
{
Str s1 = "Hello ";
Str s2;
cout << "Please enter your name: ";
cin >> s2;
Str s3 = s1 + s2 + " how are you?";
cout << s3 << endl;
return 0;
}
5 使用重写后的Str类运行使用Str类的程序做检验。
测试程序:
#include <vector>
using std::vector;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <algorithm>
using std::max;
using std::find_if;
#include "Str.h"
Str::size_type width(const vector<Str>& v)
{
Str::size_type maxlen = 0;
for (vector<Str>::size_type i = 0; i != v.size(); ++i)
maxlen = max(maxlen, v[i].size());
return maxlen;
}
vector<Str> frame(const vector<Str>& v)
{
vector<Str> ret;
Str::size_type maxlen = width(v);
Str border(maxlen + 4, '*');
ret.push_back(border);
for (vector<Str>::size_type i = 0; i != v.size(); ++i)
{
ret.push_back("* " + v[i] + Str(maxlen - v[i].size(), ' ') + " *");
}
ret.push_back(border);
return ret;
}
vector<Str> vcat(const vector<Str>& top, const vector<Str>& bottom)
{
vector<Str> ret = top;
ret.insert(ret.end(), bottom.begin(), bottom.end());
return ret;
}
vector<Str> hcat(const vector<Str>& left, const vector<Str>& right)
{
vector<Str> ret;
Str::size_type width1 = width(left) + 1;
vector<Str>::size_type i = 0, j = 0;
while (i != left.size() || j != right.size())
{
Str s;
if (i != left.size())
s = left[i++];
s += Str(width1 - s.size(), ' ');
if (j != right.size())
s += right[j++];
ret.push_back(s);
}
return ret;
}
vector<Str> center(const vector<Str>& v)
{
vector<Str> v_out;
vector<Str>::size_type maxlen = width(v);
vector<Str>::const_iterator iter = v.begin();
while (iter != v.end())
{
int spaces_l = (maxlen - iter->size()) / 2;
int spaces_r = maxlen - iter->size() - spaces_l;
if (spaces_l != 0)
v_out.push_back(Str(spaces_l, ' ') + *iter++ + Str(spaces_r, ' '));
else
v_out.push_back(*iter++);
}
return v_out;
}
vector<Str> split(const Str& s)
{
vector<Str> ret;
typedef Str::size_type Str_size;
Str_size i = 0;
while (i != s.size())
{
while (i != s.size() && isspace(s[i]))
++i;
Str_size j = i;
while (j != s.size() && !isspace(s[j]))
++j;
if (i != j)
{
ret.push_back(Str(s.begin() + i, s.begin() + j));
i = j;
}
}
return ret;
}
bool space(char c)
{
return isspace(c) != 0;
}
bool not_space(char c)
{
return !isspace(c);
}
vector<Str> split_alt(const Str& str)
{
typedef Str::const_iterator iter;
vector<Str> ret;
iter i = str.begin();
while (i != str.end())
{
i = find_if(i, str.end(), not_space);
iter j = find_if(i, str.end(), space);
if (i != str.end())
ret.push_back(Str(i, j));
i = j;
}
return ret;
}
int test_frame()
{
vector<Str> v1 = { "one test", "two test", "ohohoh yeyeyGeeGeeGee" };
vector<Str> v2 = { "i love you", "you hate me", "i pursue you", "you love other people" };
vector<Str> vert = vcat(frame(v1), frame(v2));
vector<Str>::const_iterator iter = vert.begin();
while (iter != vert.end())
cout << *iter++ << endl;
vector<Str> horz = hcat(frame(v1), frame(v2));
iter = horz.begin();
while (iter != horz.end())
cout << *iter++ << endl;
return 0;
}
int test_center()
{
vector<Str> v = { "This is really great", "really", "super awesome", "awesomejame" };
vector<Str> centered_v = center(v);
vector<Str>::const_iterator iter = centered_v.begin();
while (iter != centered_v.end())
cout << *iter++ << endl;
return 0;
}
int test_string_split()
{
Str s = "Split this string!";
vector<Str> v = split(s);
for (vector<Str>::size_type i = 0; i != v.size(); ++i)
cout << v[i] << endl;
return 0;
}
int test_string_split_alt()
{
Str s = "And this one too!";
vector<Str> v = split(s);
for (vector<Str>::size_type i = 0; i != v.size(); ++i)
cout << v[i] << endl;
return 0;
}
int main()
{
test_frame();
cout << endl;
test_center();
cout << endl;
test_string_split();
cout << endl;
test_string_split_alt();
cout << endl;
return 0;
}
6 Ptr类实际解决了两个问题:保留引用计数,为对象分配内存和释放内存。定义一个只负责引用计数的类,然后用该类重新实现Ptr类。
头文件:
//
// Created by MacBook Pro on 2020-03-20.
//
#ifndef ACM_PTR_H
#define ACM_PTR_H
#include "Refptr.h"
template <class T>T* clone(const T* tp){
return tp->clone();
}
template <class T>
class Ptr{
public:
//在需要时有条件复制对象
void make_unique(){
if(*refptr != 1){
--*refptr;
refptr = new size_t(1);
p = p?clone(p):0;
}
}
Ptr():p(0),refptr(new size_t(1)){}
Ptr(T* t):p(t),refptr(new size_t(1)){}
Ptr(const Ptr& h):p(h.p),refptr(h.refptr){++*refptr;}
Ptr& operator=(const Ptr&);
~Ptr();
operator bool() const {return p;}
T& operator*() const{
if(p) return *p;
throw std::runtime_error("unbound Ptr");
}
T* operator->() const{
if(p) return p;
throw std::runtime_error("unbound Ptr");
}
private:
T* p;
std::size_t * refptr;
};
template <class T>
Ptr<T>& Ptr<T>::operator=(const Ptr &rhs) {
++*rhs.refptr;
if(--*refptr == 0){
delete(refptr);
delete(p);
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template <class T>
Ptr<T>::~Ptr() {
if(--*refptr==0){
delete(refptr);
delete(p);
}
}
//分离计数与管理内存
template <class T>
class Ptr_r{
public:
//在需要时有条件复制对象
void make_unique(){
if(*refptr_c != 1){
--refptr_c;
refptr_c = Refptr_counter();
p = p?clone(p):0;
}
}
//构造函数
Ptr_r():p(0){}//refptr有自己的构造函数
//与实际对象绑定
Ptr_r(T* t):p(t){}
//复制构造函数
Ptr_r(const Ptr_r& h):p(h.p),refptr_c(h.refptr_c){++refptr_c;}
//赋值运算符
Ptr_r& operator=(const Ptr_r&);
//析构函数
~Ptr_r();
//条件判断
operator bool() const {return p;}
//隐藏指针
T& operator*() const{
if(p) return *p;
throw std::runtime_error("unbound Ptr_r");
}
//返回指针
T* operator->() const{
if(p) return p;
throw std::runtime_error("unbound Ptr_r");
}
private:
T* p;
Refptr_counter refptr_c;
};
template <class T>
Ptr_r<T>& Ptr_r<T>::operator=(const Ptr_r &rhs) {
++(*rhs.refptr_c);
if(*(--refptr_c) == 0){
// delete(refptr);//refptr析构函数会执行
delete(p);
}
refptr_c = rhs.refptr_c;
p = rhs.p;
return *this;
}
template <class T>
Ptr_r<T>::~Ptr_r() {
if(*(--refptr_c) ==0){
// delete(refptr);//refptr析构函数会执行
delete(p);
}
}
class Student_info{
public:
Student_info(){}
Student_info(std::istream& is){ read(is);}
std::istream& read(std::istream&);
std::string name() const{
if(cp) return cp->name();
else throw std::runtime_error("uninitialized Student");
}
double grade() const{
if(cp) return cp->grade();
else throw std::runtime_error("uninitialized Student");
}
static bool compare(const Student_info& s1, const Student_info& s2){
return s1.name() < s2.name();
}
void regrade(double final, double thesis){
//改变时,先得到副本
cp.make_unique();
if(cp) cp->regrade(final, thesis);
else throw std::runtime_error("regrade of unknown students");
}
private:
// Handle<Core> cp;
Ptr<Core> cp;
};
std::istream& Student_info::read(std::istream& is){
与之前的不同,删除了这句话,因为对cp进行赋值会释放对象暂用的内存
//Hanle类的赋值运算符函数会在赋值给cp的时候,自动删除Handle此前所指的对象
// delete cp;//如果有的话,删除所指对象,删除一个零指针也是无害的
char ch;
is >> ch;
if(ch == 'U') cp = new Core(is);
else cp = new Grad(is);
return is;
}
#endif //ACM_PTR_H
//
// Created by MacBook Pro on 2020-03-20.
//
#ifndef ACM_REFPTR_H
#define ACM_REFPTR_H
#include <cstddef>
class Refptr_counter{
public:
//构造
Refptr_counter():counter(new std::size_t(1)){}
Refptr_counter(std::size_t s):counter(new std::size_t(s)){}
//复制构造
Refptr_counter(const Refptr_counter& h):counter(h.counter){}
//赋值运算符
Refptr_counter& operator=(const Refptr_counter& rhs){
if(*counter <= 0){
delete counter;
}
counter = rhs.counter;
return *this;
};
//析构函数
~Refptr_counter(){
if(*counter <= 0) delete counter;
}
//运算符函数
//前缀
Refptr_counter& operator++(){
(*counter)++;
return *this;
}
Refptr_counter&operator--(){
(*counter)--;
return *this;
}
//后缀(返回临时变量)
Refptr_counter operator++(int){
Refptr_counter res(*(this->counter));//复制构造函数
(*counter)++;
return res;
}
Refptr_counter operator--(int){
Refptr_counter res = *this;//赋值构造函数
(*counter)--;
return res;
}
//返回计数值
std::size_t operator*() const{
return *counter;
}
private:
std::size_t* counter;
};
#endif //ACM_REFPTR_H
源文件:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <string>
#include "Student_info.h"
#include "Ptr.h"
#include <fstream>
#include <sstream>
using std::stringstream;
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::domain_error;
using std::vector;
using std::min;
using std::string;
using std::max;
using std::streamsize;
using std::setprecision;
using std::sort;
using std::string;
std::string Core::name() const {
#if ANNOTATE == 1
std::cerr<<" Core::name() "<<std::endl;
#endif
return n;}
istream& Core::read_common(istream& in){
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in){
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in){
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
//不能将重载函数命名为模版参数,不然编译器无法决定调用按一个版本
//指向Core类型的指针,也可以将指向Grad的指针传给它,编译器会转换为Core*
bool compare(const Core& c1, const Core& c2){
return c1.name() < c2.name();
}
//Handle类调用
//bool compare_Core_handles(const Handle<Core> cp1, const Handle<Core> cp2){
// return compare(*cp1, *cp2);
//}
//bool compare_Core_Ptr(const Ptr<Core> cp1, const Ptr<Core> cp2){
// return compare(*cp1, *cp2);
//}
bool compare_grades(const Core& c1, const Core& c2){
return c1.grade() < c2.grade();
}
double Core::grade() const{
#if ANNOTATE == 1
std::cerr<<" Core::grade()"<<std::endl;
#endif
return ::grade(midterm, final, homework);
}
double Grad::grade() const {
#if ANNOTATE == 1
std::cerr<<" Grad::grade()"<<std::endl;
#endif
return min(Core::grade(), thesis);//显示表明
}
double median(vector<double> vec){
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
string Core::letter_grade() const {
static const double numbers[]={
97, 94, 90, 87, 84, 80, 77, 74, 70, 60, 0
};
static const char* const letters[]={
"A+","A","A-","B+","B","B-","C+","C","C-","D","F"
};
//计算成绩的个数
static const size_t ngrades = sizeof(numbers)/sizeof(*numbers);
double result = grade();
for (size_t i = 0; i < ngrades; ++i) {
if(result >= numbers[i]){
return letters[i];
}
}
return "? \? \?";
}
double Credit::grade() const {
if(homework.empty()){
return (midterm + final)/2;
}else{
return Core::grade();
}
}
istream& Audit::read(std::istream &is) {
Core* record;
char ch;
maxlen = 0;
while(is >> ch) {
if (ch == 'U') {
record = new Core;//为一个Core类型对象分配内存
} else{
record = new Grad;//为一个Grad类型对象分配内存
}
record->read(is);//虚拟调用
maxlen = max(maxlen, record->name().size());
students_garde[record->name()] = record->grade();
}
return is;
}
double Audit::checked(const std::string & name) const {
const_iterator iter = students_garde.find(name);
if(iter != students_garde.end()){
return iter->second;
}else{
return -1;
}
}
int main(int argc, char** argv){
vector<Student_info> students;
Student_info record;
char ch;
string::size_type maxlen = 0;
std::ifstream infile("/Users/macbookpro/CLionProjects/ACM/students10.txt");
while(record.read(infile)){
maxlen = max(maxlen, record.name().size());
students.push_back(record);
}
infile.close();
infile.clear();
sort(students.begin(), students.end(), Student_info::compare);
for (vector<Student_info>::size_type i = 0; i != students.size(); ++i) {
cout << students[i].name()
<< string(maxlen + 1 - students[i].name().size(),' ');
try{
double final_grade = students[i].grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
}catch(domain_error e){
cout << e.what() <<endl;
}
}
return 0;
}