Accelerated C++ 15 Revisiting character pictures

grade.h

#ifndef GUARD_grade_h
#define GUARD_grade_h

// grade.h
#include <vector>

double median(std::vector<double>);

double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double grade(const Student_info&);

#endif

grade.cpp

// source file for the grade-ralated functons
#include <vector>
#include <stdexcept>
#include "Student_info.h"
#include "median.h"

using std::vector;  using std::domain_error; using std::sort;

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 - 1] + vec[mid]) / 2 : vec[mid];
}

double grade(double midterm, double final, double homework) {
    return 0.2 * midterm + 0.4 * final + 0.4 * homework;
}

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

double grade(const Student_info& s) {
    return grade(s.midterm, s.final, s.homework);
}

Student_info.h

#ifndef GUARD_Student_info
#define GUARD_Student_info

// Student_info.h header file
#include <iostream>
#include <string>
#include <vector>

class Student_info{
public:
    std::string name() const {
        return n;
    }
    std::istream& read(std::istream&);
    double grade() const;
    static bool compare(const Student_info&, const Student_info&);
private:
    std::string n;
    double midterm, final;
    std::vector<double>  homework;

};

#endif

Student_info.cpp

// source file for Student_info-related functions
#include <vector>
#include <iostream>
#include "Student_info.h"
#include "grade.h"

using std::cout;    using std::vector;  using std::istream;

double Student_info::grade() const {
    return ::grade(midterm, final, homework);
}

bool Student_info::compare(const Student_info& x, const Student_info& y) {
    return x.n < y.n;
}

istream& read_hw(istream& in, vector<double>& hw) {
    // read and store the homework grades
    cout << "Enter all your homework grades, "
            "followd by end-of-file: ";
    if (in) {
        // get rid of previous contents
        hw.clear();

        // read homework grades
        double x;
        while (in >> x)
            hw.push_back(x);

        // clear the stream so that input will work for the next student
        in.clear();
    }
    return in;
}

istream& Student_info::read(istream& is) {
    // read and store the student's name and midterm and final exam grades
    cout << "Please enter your first name, midterm and final exam grades: ";
    is >> n >> midterm >> final;
    read_hw(is, homework);
    return is;
}

Pic.h

#ifndef GUARD_Pic_h
#define GUARD_Pic_h

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include "Ptr.h"

// forward declaration
class Picture;

class Pic_base {
    friend std::ostream& operator<<(std::ostream&, const Picture&);
    friend class Frame_Pic;
    friend class HCat_Pic;
    friend class VCat_Pic;
    friend class String_Pic;

    private:
        // no public interface(except for the destrctor)
        typedef std::vector<std::string>::size_type ht_sz;          
        typedef std::string::size_type wd_sz;                                                      
        virtual wd_sz width() const = 0;
        virtual ht_sz height() const = 0;
        virtual void display(std::ostream&, ht_sz, bool) const = 0;
    public:
        virtual ~Pic_base() { }
    protected:
        static void pad(std::ostream&, wd_sz, wd_sz);
};

void Pic_base::pad(std::ostream& os, wd_sz beg, wd_sz end) {
    while (beg != end) {
        os << " ";
        ++beg;
    }
}


class Frame_Pic: public Pic_base {
    friend Picture frame(const Picture&);
    // no public interface
    Ptr<Pic_base> p;
    Frame_Pic(const Ptr<Pic_base>& pic): p(pic) { }

    wd_sz width() const { return p->width() + 4; }
    ht_sz height() const { return p->height() + 4; }
    void display(std::ostream&, ht_sz, bool) const;
};

void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
    if (row >= height()) {

        // out of range
        if (do_pad)
            pad(os, 0, width());
    } else if (row == 0 || row == height() - 1) {

        // top or bottom row
        os << std::string(width(), '*');
    } else if (row == 1 || row == height() - 2) {

        // second from top or bottom row
        os << "*";
        pad(os, 1, width() - 1);
        os << "*";
    } else {

        // interior row
        os << "* ";
        p->display(os, row - 2, true);
        os << " *";
    }
}


class VCat_Pic: public Pic_base {
    friend Picture vcat(const Picture&, const Picture&);
    Ptr<Pic_base> top, bottom;
    VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b):
        top(t), bottom(b) { }

    wd_sz width() const {
        return std::max(top->width(), bottom->width());
    }

    ht_sz height() const{
        return top->height() + bottom->height();
    }

    void display(std::ostream&, ht_sz, bool) const;
};

void VCat_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
    wd_sz w = 0;
    if (row < top->height()) {

        // we are in the top subpicture
        top->display(os, row, do_pad);
        w = top->width();
    } else if (row < height()) {

        // we are in the bottom subpicture
        bottom->display(os, row - top->height(), do_pad);
        w = bottom->width();
    }
    if (do_pad)
        pad(os, w, width());
}

class HCat_Pic: public Pic_base {
    friend Picture hcat(const Picture&, const Picture&);

    Ptr<Pic_base> left, right;
    HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r):
        left(l), right(r) { }

    wd_sz width() const {
        return left->width() + right->width();
    }

    ht_sz height() const {
        return std::max(left->height(), right->height());
    }

    void display(std::ostream&, ht_sz, bool) const;
};

void HCat_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
    left->display(os, row, do_pad || row < right->height());
    right->display(os, row, do_pad);
}

class String_Pic: public Pic_base {
    friend class Picture;

    std::vector<std::string> data;
    String_Pic(const std::vector<std::string>& v): data(v) { }

    wd_sz width() const;
    ht_sz height() const { return data.size(); }
    void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz String_Pic::width() const {
    Pic_base::wd_sz n = 0;
    for (Pic_base::ht_sz i = 0; i != data.size(); ++i)
        n = std::max(n, data[i].size());
    return n;
}

void String_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
    wd_sz start = 0;

    // write the row if we're still in range
    if (row < height()) {
        os << data[row];
        start = data[row].size();
    }

    // pad the output if necessary
    if (do_pad)
        pad(os, start, width());
}

class Picture {
    friend std::ostream& operator<<(std::ostream&, const Picture&);
    friend Picture frame(const Picture&);
    friend Picture hcat(const Picture&, const Picture&);
    friend Picture vcat(const Picture&, const Picture&);



    public:
        Picture(const std::vector<std::string>& v = std::vector<std::string>()): p(new String_Pic(v)) { }

    private:
        Picture(Pic_base* ptr): p(ptr) { }
        Ptr<Pic_base> p;
};

Picture frame(const Picture& pic) {
    return new Frame_Pic(pic.p);
}

Picture hcat(const Picture& l, const Picture& r) {
    return new HCat_Pic(l.p, r.p);
}

Picture vcat(const Picture& t, const Picture& b) {
    return new VCat_Pic(t.p, b.p);
}

std::ostream& operator<<(std::ostream& os, const Picture& picture) {
    const Pic_base::ht_sz ht = picture.p->height();
    std::endl;
    for (Pic_base::ht_sz i = 0; i != ht; ++i) {
        picture.p->display(os, i, false);
        os << std::endl;
    }
    return os;
}

#endif

Ptr.h

#ifndef GUARD_Ptr_h
#define GUARD_Ptr_h

// Ptr.h
#include <iostream>
#include <stdexcept>

template <typename T> class Ptr {
    public:
        // new member to copy the object conditionally when needed
        void make_unique() {
            if (*refptr != 1) {
                --*refptr;
                refptr = new size_t(1);
                p = p ? p->clone() : 0;
            }
        }

        // same as Ref_handle
        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; 
        T* operator->() const {
            if (p)
                return p;
            throw std::runtime_error("unbound Ptr");
        }

    private:
        T* p;
        std::size_t* refptr;
};

template <typename T> 
Ptr<T>& Ptr<T>::operator=(const Ptr& rhs) {
    ++*rhs.refptr;

    // free the left-hand side, destroying pointers if appropriate
    if (--*refptr == 0) {
        delete refptr;
        delete p;
    }

    // copy in values from the right-hand side
    refptr = rhs.refptr;
    p = rhs.p;
    return *this;
}

template <typename T>
T& Ptr<T>::operator*() const {
    if (p)
        return *p;
    throw std::runtime_error("unbound Ptr");
}

template <typename T>
Ptr<T>::~Ptr() {
    if (--*refptr == 0) {
        delete refptr;
        delete p;
    }
}

#endif

main.cpp

// main.cpp
#include "Pic.h"
// #include "median.h"
// #include "grade.h"
// #include "Ptr.h"
#include "Student_info.h"
#include <algorithm>

using std::vector;  using std::string;  using std::cin;
using std::cout;    using std::endl;    using std::sort;
Picture histogram(const vector<Student_info>& students) {
    Picture names;
    Picture grades;

    // for each student
    for (vector<Student_info>::const_iterator it = students.begin(); it != students.end(); ++it) {

        // create vertically concatenated pictures of the names and grades
        names = vcat(names, vector<string>(1, it->name()));
        grades = vcat(grades,
                vector<string>(1, " " + string(it->grade() / 5, '=')));
    }

    // horizontally concatenate the name and grade pictures to combine them
    return hcat(names, grades);
}

int main() {
    vector<Student_info> students;
    Student_info s;

    // read the names and grades
    while (s.read(cin))
        students.push_back(s);

    // put the students in alphabetical order
    sort(students.begin(), students.end(), Student_info::compare);

    // write the names and histograms
    cout << frame(histogram(students)) << endl;
    return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值