第十四章习题 近乎自动地管理内存

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值