chapter-7

// 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成员函数为常量返回类型!(常量版本的函数),程序有必要同时定义一个非常量版本的函数!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容