【足迹C++ primer】17、类的其他特性(2)

类的其他特性(2)

返回*this的成员函数

返回*this的成员函数,则调用的直接就是类的对象本身,而不是他的副本。
#include<iostream>
#include<vector>

using namespace std;

class Screen
{
public:
    typedef std::string::size_type pos;     //用pos来代表这个类型
//  using pos=std::string::size_type;   同上等价

    Screen &set(char);
    Screen &set(pos, pos, char);

    Screen()=default;   //因为Screen有另一个构造函数,所以本函数是必须的,默认方式
    Screen(pos ht, pos wd, char c):height(ht), width(wd),

    contents(ht*wd,c){}    //contents初始化的意思是,有ht乘wd个字符c初始化一个string类型

    char get() const        //读取光标处的字符
    {
        return contents[cursor];    //隐式内联
    }
    inline char get(pos ht, pos wd) const;  //显式内联

    Screen &move(pos r, pos c);     //能在之后被设为内联

    void some_member() const;
private:
    pos cursor=0;
    pos height=0, width=0;
    std::string contents;
    mutable size_t access_ctr;      //即使在一个const对象内也能被修改

};

inline Screen &Screen::set(char c)
{
    contents[cursor]=c;         //设置当前光标所在位置的新值
    return *this;           //将this对象作为左值返回
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
    contents[r*width+col]=ch;       //设置给定位置的新值
    return *this;                   //将this对象作为左值返回
}

//虽然我们没必要在类的里面和外面都用inline来声明,但是这样
//是合法的,不过最好只在类的外部说明inline,这样更容易理解

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    //在类的内部声明成inline
{
    pos row=r*width;        //计算行的位置
    return contents[row+c];     //返回给定列的字符
}

void Screen::some_member() const
{
    ++access_ctr;       //保管一个计数值,用于记录成员函数被调用的次数
}


class Window_mgr
{
private:
    //这个Window_mgr追踪的Screen
    //默认情况下,一个Window_mgr包含一个标准尺寸的空白Screen
    std::vector<Screen> screens{Screen(24, 80, ' ')};
};

class Sales_data
{
public:
    void avg_price();
};

inline
void Sales_data::avg_price()
{

}

int main()
{
    Screen myScreen;
    myScreen.move(4,0).set('#');
    //上面等价于
    //myScreen.move(4,0);
    //myScreen.set('#');
}


从const成员函数返回*this

我们继续添加一个操作,叫display,负责打印Screen的内容,返回的是const类型的。
但是这样的话,返回后就无法进行操作了,因为返回的类型是const的类型。

基于const的重载

由于非常量版本的函数对于常量对象是不可用的,所以我们只能在一个常量对象上调用const成员函数
这里我们就定义一个名为do_display的私有成员,由它负责打印Screen的实际工作。所有的display操作都将调用这个函数
Screen &display(std::ostream &os)
    {
        do_diaplay(os);
        return *this;
    }
    const Screen &display(std::ostream &os) const
    {
        do_diaplay(os);
        return *this;
    }    

私有成员是:
 void do_diaplay(std::ostream &os) const
    {
        os<<contents;
    }

为什么要这样写呢?
因为当一个成员调用另外一个成员时,this指针在其中隐式地传递。因此,当display调用do_diaplay时,它的this指针隐式地传递给do_diaplay。
而当display非常量版本调用do_diaplay的时候,它的this指针将隐式地从指向非常量的指针转换成指向常量的指针。
当do_diaplay完成后,display函数各自返回解引用this所得的对象。
    Screen myScreen(5,3,'c');
    const Screen blank(5,3,'b');
    
    myScreen.move(4,0).set('#');
    //上面等价于
    //myScreen.move(4,0);
    //myScreen.set('#');
    myScreen.set('#').display(cout);    //调用非常量版本
    blank.display(cout);                //调用非常量版本    

类类型

即使两个类的成员一模一样,他们也是两个不同的类型
习题:7.31
class X;
class Y
{
    X *p;
};

class X
{
    Y *p;
};


友元再探

类之间的友元关系
//Window_mgr的成员可以访问Screen类的私有部分
    friend class Window_mgr;

class Window_mgr
{
private:
    //这个Window_mgr追踪的Screen
    //默认情况下,一个Window_mgr包含一个标准尺寸的空白Screen
    std::vector<Screen> screens{Screen(24, 80, ' ')};
public:
    //窗口中每个屏幕的编号
    using ScreenIndex=std::vector<Screen>::size_type;
    //按编号将指定的Screen重置为空白
    void clear(ScreenIndex);
};

void Window_mgr::clear(ScreenIndex i)
{
    //s是一个Screen的引用,指向我们想清空的那个屏幕
    Screen &s=screens[i];
    //将那个选定的Screen重置为空白
    s.contents=string(s.height*s.width, '');
}

函数重载和友元

extern std::ostream& storeOn(std::ostream &, Screen &);
extern BitMap& storeOn(BitMap &, Screen &);

class Screen里面
friend std::ostream& storeOn(std::ostream &, Screen &);

全部代码实现:

/*
* 功能:类的前向声明,和友元,函数声明
* 时间:2014年6月2日16:38:51
* 作者:cutter_point
*/

#include<iostream>
#include<vector>
#include<string>

using namespace std;

class Window_mgr;

class Screen
{
public:
    typedef std::string::size_type pos;     //用pos来代表这个类型
//  using pos=std::string::size_type;   同上等价

    Screen &set(char);
    Screen &set(pos, pos, char);
    Screen &move(pos r, pos c);     //能在之后被设为内联
//  cosnt Screen &display() const;
    Screen &display(std::ostream &os)
    {
        do_diaplay(os);
        return *this;
    }
    const Screen &display(std::ostream &os) const
    {
        do_diaplay(os);
        return *this;
    }

    Screen()=default;   //因为Screen有另一个构造函数,所以本函数是必须的,默认方式
    Screen(pos ht, pos wd, char c):height(ht), width(wd),

    contents(ht*wd,c){}    //contents初始化的意思是,有ht乘wd个字符c初始化一个string类型

    char get() const        //读取光标处的字符
    {
        return contents[cursor];    //隐式内联
    }
    inline char get(pos ht, pos wd) const;  //显式内联

    void some_member() const;

    //Window_mgr的成员可以访问Screen类的私有部分
    friend class Window_mgr;
    using ScreenIndex=std::vector<Screen>::size_type;
    //注意这里是函数声明不要在函数前面加Window_mgr::clear不然这事错的,你还要定义在
    //类Window_mgr里面,在前面定义的话后面的私有成员又不好搞了!!!
    friend void clear(ScreenIndex);
    friend std::ostream& storeOn(std::ostream &, Screen &);
private:
    pos cursor=0;
    pos height=0, width=0;
    std::string contents;
    mutable size_t access_ctr;      //即使在一个const对象内也能被修改
    //该函数负责显示Screen的内容
    void do_diaplay(std::ostream &os) const
    {
        os<<contents;
    }

};

/*
Screen &Screen::display()
{
    return *this;
}
*/

inline Screen &Screen::set(char c)
{
    contents[cursor]=c;         //设置当前光标所在位置的新值
    return *this;           //将this对象作为左值返回
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
    contents[r*width+col]=ch;       //设置给定位置的新值
    return *this;                   //将this对象作为左值返回
}

//虽然我们没必要在类的里面和外面都用inline来声明,但是这样
//是合法的,不过最好只在类的外部说明inline,这样更容易理解

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    //在类的内部声明成inline
{
    pos row=r*width;        //计算行的位置
    return contents[row+c];     //返回给定列的字符
}

void Screen::some_member() const
{
    ++access_ctr;       //保管一个计数值,用于记录成员函数被调用的次数
}


class Window_mgr
{
public:
    //窗口中每个屏幕的编号
    using ScreenIndex=std::vector<Screen>::size_type;
    //按编号将指定的Screen重置为空白
    void clear(ScreenIndex);
private:
    //这个Window_mgr追踪的Screen
    //默认情况下,一个Window_mgr包含一个标准尺寸的空白Screen
    std::vector<Screen> screens{Screen(24, 80, ' ')};
};

void Window_mgr::clear(ScreenIndex i)
{
    //s是一个Screen的引用,指向我们想清空的那个屏幕
    Screen &s=screens[i];
    //将那个选定的Screen重置为空白
    s.contents=string(s.height*s.width, ' ');
}


class Sales_data
{
public:
    void avg_price();
};

inline
void Sales_data::avg_price()
{

}

int main()
{
   // Screen myScreen;
    Screen myScreen(5,3,'c');
    const Screen blank(5,3,'b');

    myScreen.move(4,0).set('#');
    //上面等价于
    //myScreen.move(4,0);
    //myScreen.set('#');
    myScreen.set('#').display(cout);    //调用非常量版本
    blank.display(cout);                //调用非常量版本

    return 0;
}

/************************************************************************/
/*
class X;
class Y
{
    X *p;
};

class X
{
    Y *p;
};
*/
class BitMap;

extern std::ostream& storeOn(std::ostream &, Screen &);
extern BitMap& storeOn(BitMap &, Screen &);


PS:这几天有事回老家了,没网没电脑,所以搞不了,现在越来越觉得自己真是什么都不会,以后出去怎么搞啊!!!!哎,这个暑假本来不想出去搞的,但是貌似的出去做暑假工,去找实习的话这水平估计没公司要委屈委屈委屈哭哭哭,好伤心啊!!!
















  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值