chapter-7

作者: 峡迩 | 来源:发表于2017-07-13 22:30 被阅读0次
    // chapter-7.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include<iostream>
    #include<string>
    #include<vector>
    
    using namespace std;
    
    class Sales_data                                    //第一个访问说明符之前的成员属性由class和struct决定,class默认private,struct默认public
    {
        // 定义友元,外部函数可以访问非共有成员(protected,private)
        friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
        friend ostream &print(ostream &os, Sales_data &item);   //声明为其友元函数,可以访问非共有成员。(友元声明并不是一个完整意义的函数声明!)
        friend istream &read(istream &is, Sales_data &item);
    
    public:                                             //都可访问
    
        //构造函数
        Sales_data() = default;                         //只有当类没有声明任何构造函数时,才会自动生成默认构造函数
        Sales_data(const string &s) :bookNo(s) {};
        Sales_data(const string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(p*n) {};
        Sales_data(istream &);
    
        string isbn() const { return bookNo; };         //默认使用this,等价于this->bookNo;使用const改变this指针为指向常量(底层const)的常量指针(this默认为常量指针(顶层const)),提高函数的灵活性!指向常量的常量指针函数,才可以使常量对象调用普通成员函数!此函数有前提条件,在函数体内不会改变this所指向的对象!
        Sales_data &combine(const Sales_data&);
        double avg_price() const;
    //protected:                                            //外部不可访问,继承可以访问!
    
      private:                                          //外部和继承不可访问,使用封装有2个重要的好处:1、确保用户不会无意间破坏封装对象;2、被封住的类具体实现细节可以随时修改,而无须调整用户级别的代码。
        string bookNo;
        unsigned units_sold = 0;
        double revenue = 0.0;
    };
    
    //Sales_data非成员接口函数
    Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
    ostream &print(ostream &os, Sales_data &item);          //函数声明时候,形参等必须相同!
    istream &read(istream &is, Sales_data &item);
    
    double Sales_data::avg_price()const
    {
        if (units_sold)
            return revenue / units_sold;
        else
        {
            return 0;
        }
    }
    
    Sales_data& Sales_data::combine(const Sales_data &rhs)
    {
        units_sold += rhs.units_sold;
        revenue += rhs.revenue;
        return *this;                                       //返回调用该函数的对象。
    }
    
    istream &read(istream &is, Sales_data &item)
    {
        double price = 0;
        is >> item.bookNo >> item.units_sold >> price;
        item.revenue = price*item.units_sold;
        return is;
    }
    
    //Sales_data(istream &)构造函数
    Sales_data::Sales_data(istream &is)
    {
        read(is, *this);
    }
    
    ostream &print(ostream &os, Sales_data &item)
    {
        os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
        return os;
    }
    
    Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
    {
        Sales_data item = lhs;
        item.combine(rhs);
        return item;
    }
    
    class Screen
    {
        friend class window_mgr;                //定义window_mgr为screen的友元类!,则window_mgr中的函数可以访问screen中的非公有成员!
                                                //友元关系不存在传递关系,每个类定义自己的友元!
    public:
        using pos = string::size_type;
        Screen() = default;
        Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {}
        char get()const                                 //隐式内联
        {
            return contents[cursor];    
        }
        inline char get(pos ht, pos wd) const;          //类内成员函数是自动的inline,也可以用inline直接声明内联函数。
        Screen &move(pos r, pos c);
    
        Screen &set(char c)
        {
            contents[cursor] = c;
            return *this;
        }
        Screen &set(pos r, pos col, char ch)            //返回*this对象的引用(即对象本身)
        {
            contents[r*width + col] = ch;
            return *this;
        }
    
        Screen &displsy(ostream &os)                //只能传入非常量版本,返回类型为非常量的引用!
        {
            do_display(os);
            return *this;
        }
        const Screen &displsy(ostream &os) const            //如果为const成员函数,则返回类型将是常量!????有什么问题没???
        {
            do_display(os);
            return *this;
        }
    
        void some_member()const;
    
    private:
        pos cursor = 0;
        pos height = 0, width = 0;
        string contents;
    
        mutable pos access_ctr = 0;
    
        void do_display(ostream &os) const { os << contents; }
    };
    
    void Screen::some_member() const
    {
        ++access_ctr;               //变量声明为可变数据成员,即使在const成员函数,还是可以改变access_ctr的值!
    }
    
    inline Screen &Screen::move(pos r, pos c)
    {
        pos row = r*width;
        cursor = row + c;
        return *this;
    }
    char Screen::get(pos r, pos c) const
    {
        pos row = r*width;
        return contents[row + c];
    }
    
    class window_mgr
    {
    public:
        void clear(vector<Screen>::size_type i)
        {
            Screen &s = screens[i];
            s.contents = string(s.height*s.width, ' ');
        }
    private:
        vector<Screen> screens{ Screen(24,80,' ') };            //类作为类内数据成员时,初始化方法!
    };
    
    class ConstRef
    {
    public:
        ConstRef() = default;
        ConstRef(int i):ii(i),ci(i),ri(i){}             //引用和const必须初始化!建议养成构造函数初始化的习惯!
    private:
        int ii;
        const int ci;
        int &ri;
    };
    
    class Data
    {
    public:
        //非委托构造函数
        Data(string s,string::size_type i,double p):item(s),cnt(i),price(p){}
        //委托构造函数
        Data():Data(" ",0,0){}
        Data(string s):Data(s,0,0){}
        Data(istream &is) :Data() { is >> item; }
    private:
        string item;
        string::size_type cnt=0;
        double price=0.0;
    };
    //聚合类,所有成员都是public,没有定义任何构造函数,没有类内初始值,没有基类也没有virtual函数!使用花括号进行成员初始化
    struct Data
    {
            int ival;
            string s;
    }
    Data val9={0,"Anna"};
    int main()
    {
        Sales_data s1(cin);             //使用构造函数Sales_data(istream &)创建对象
    
    
        Screen myscreen(5, 3,' ');
        const Screen myscreen_const(5,3,' ');       //常量screen对象。
        myscreen.set('#').displsy(cout);
        cout << endl;
        myscreen_const.displsy(cout);               //调用常量版本函数
    
        //Data obj1();
        //Data obj2;                                直接使用这种声明,定义一个默认初始化的对象!
    
        cin.ignore();
        return 0;
    }
    
    //类基本思想是数据抽象和封装。数据抽象依赖于接口和实现,接口包含用户所能执行的操作,实现包含类的数据成员、函数;封装实现了接口和实现的分离,用户只可以访问接口,而无法访问实现!
    //类的定义分两步,1、编译成员声明;2、直到类全部可见后才编译函数体。
    //类的构造函数,如果成员对象为const或者引用,则必须进行初始化!
    //类的静态成员,所有类对象共用,可以通过对象、引用或者指针访问它~在类内声明,在类外定义!
    //优秀的设计者应该关注那些有可能使用该类的程序员的需求,作为一个设计良好的类,既要有直观且易于使用的接口,也必须具备高效的实现过程!
    

    const在函数形参,实参,返回类型的区别?
    const int &i,常量引用形参!,在类内const成员函数为常量返回类型!(常量版本的函数),程序有必要同时定义一个非常量版本的函数!

    相关文章

      网友评论

          本文标题:chapter-7

          本文链接:https://www.haomeiwen.com/subject/gziehxtx.html