类的其他特性

来源:互联网 发布:人工智能的产品有哪些 编辑:程序博客网 时间:2024/06/07 08:37
#include <iostream>#include <string>using namespace std;class Screen{public:    typedef std::string::size_type pos;    //  using pos=std::string::size_type;   同上等价    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);     //能在之后被设为内联private:    pos cursor = 0;    pos height = 0, width = 0;    std::string contents;};//虽然我们没必要在类的里面和外面都用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];     //返回给定列的字符}int main(){    Screen p(10, 10,'a');    char k = p.get(5,7);    cout << k << endl;    return 0;}

内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理

内联说明(inline specification)对于编译器来说只是一个建议,编译器可以选择忽略这个建议

    char k = p.get(5,7);00CD6435  push        7  00CD6437  push        5  00CD6439  lea         ecx,[ebp-3Ch]  //采用的调用的方式来调用内联函数,所以说明内联函数没有嵌入到调用处00CD643C  call        00CD14D8  00CD6441  mov         byte ptr [ebp-45h],al  

可变数据成员

使用关键字mutable,这样一个const成员函数也可以改变一个可变成员的值了
类内初始值就是把类内部的数据进行默认初始化,要么放在花括号里面,要么放在=号右边,不能使用圆括号

class Screen{public:    typedef std::string::size_type pos;//  using pos=std::string::size_type;   同上等价    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来声明,但是这样//是合法的,不过最好只在类的外部说明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, ' ')};};

返回*this的成员函数

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

#include <iostream>#include <string>using namespace std;class Screen{public:    typedef std::string::size_type index;    Screen(index ht = 0, index wd = 0) :contents(ht*wd, 'A'), cursor(0), height(ht), width(wd)    {}    char get() const{ return contents[cursor]; }    char get(index r, index c)const    {        index row = r*width;        return contents[row + c];    }    Screen& move(index r, index c);    Screen& set(index, index, char);    Screen& set(char);private:    std::string contents;    index cursor;    index height, width;};Screen& Screen::move(index r, index c){    index row = r*width;    cursor = row + c;    return *this;}Screen& Screen::set(index r, index c, char ch){    index row = r*width;    contents[row + c] = ch;    return *this;}Screen& Screen::set(char c){    contents[cursor] = c;    return *this;}int main(){    Screen myScreen(5, 5);    myScreen.move(4, 0).set('#');    cout << myScreen.get() << endl;}

从const成员函数返回*this
在普通的非const成员函数中,this的类型是一个指向类类型的const指针,可以改变this所指向的值,但不能改变this所保存的地址。在const成员函数中,this的类型是一个指向const类类型的const指针,既不能改变this所指向的对象,也不能改变this所保存的地址

不能从const所员函数返回指向类对象的普通引用。const成员函数只能返回*this作为一个const 引用。

基于const的重载:

#include <iostream>#include <string>using namespace std;class Screen{public:    typedef std::string::size_type index;    Screen(index ht = 0, index wd = 0) :contents(ht*wd, 'A'), cursor(0), height(ht), width(wd)    {}    char get() const{ return contents[cursor]; }    char get(index r, index c)const    {        index row = r*width;        return contents[row + c];    }    Screen& move(index r, index c);    Screen& set(index, index, char);    Screen& set(char);    const Screen& display(std::ostream &os)const    {        do_display(os);        return *this;    }    Screen& display(std::ostream &os)    {        do_display(os);        return *this;    }private:    std::string contents;    index cursor;    index height, width;    void do_display(std::ostream &os)const    {        os << contents;    }};Screen& Screen::move(index r, index c){    index row = r*width;    cursor = row + c;    return *this;}Screen& Screen::set(index r, index c, char ch){    index row = r*width;    contents[row + c] = ch;    return *this;}Screen& Screen::set(char c){    contents[cursor] = c;    return *this;}int main(){    Screen myScreen(3, 3);    myScreen.display(cout).set('#').display(cout);    cout << endl;    const Screen blank(3, 3);    myScreen.set('#').display(cout);//调用非常量版本    cout << endl;    blank.display(cout);//调用常量版本    return 0;}

书本P144说:允许指向非常量类型指针转换成指向相应的常量类型指针,对于引用也是这样。也就是说,如果T是一种类型,我们就能将指向T的指针或引用分别装换成指向const T的指针或类型。
一个成员调用另一个成员时,this指针在其中隐式地传递。因此,当display调用do_display时,它的this指针将隐式地从指向非常量的指针转换成指向常量的指针。当do_display完成后,display函数各自解引用this所得的对象。在非常量版本中,this指向一个非常量对象,因此display返回一个普通的(非常量)引用;而const成员则返回一个常量引用。

0 0
原创粉丝点击