zoukankan      html  css  js  c++  java
  • 【c++ primer, 5e】类的其他特性

    【Class Members Revisited】

    1、Defining a Type Member:

    #include <iostream>
    #include <string>
    
    using namespace std;
    class Screen {
    public:
        using pos = string::size_type;
        /*
            这就是“类型成员”,必须先定义后使用(p232)
            等价声明: typedef string::size_type pos;
            string::size_type 一般是 unsigned int
        */
    private:
        pos cursor = 0; // 光标的位置
        pos height = 0, width = 0; // 屏幕的高和宽
        string contents; // 保存内容
    };
    
    int main()
    {
        return 0;
    }

    2、Member Functions of class Screen。

    class 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];
        } // implicitly inline
        inline char get(pos ht, pos wd) const; // explicitly inline
        Screen &move(pos r, pos c);
    private:
        pos cursor = 0;
        pos height = 0, width = 0;
        string contents;
    };

    3、Making Members inline

     规模小的成员函数适合被声明为inline,例如上面的构造器和其中一个get函数默认是内联的。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 {
        pos row = r * width;
        return contents[row+c];
    }

    需要注意的是内联函数应当和相应的类定义在同一个头文件中。

    4、Overloading Member Functions

        Screen myscreen;
        char ch = myscreen.get(); // calls Screen::get()
        ch = myscreen.get(0,0); // calls Screen::get(pos,pos)

    5、mutable Data Members

    极少的一种情况(例如记录const函数被调用的次数),我们希望在const成员函数中修改类的数据成员。(正常情况下是做不到的,const函数不能修改数据成员)这个时候,可以将变量声明成mutable来做到这一点。

    public:
        void some_member() const {
            ++access_ctr;
        }
    private:
        size_t access_ctr;

    这种情况无法通过编译:

    prog1.cpp: In member function 'void Screen::some_member() const':
    prog1.cpp:20:5: error: increment of member 'Screen::access_ctr' in read-only object
       ++access_ctr;

    把access_cstr声明成mutable即可:

    mutable size_t access_ctr;

    6、Initializers for Data Members of Class Type

    class Window_mgr {
    private:
        vector<Screen> screens{Screen(24, 80, ' ')};
    };

    类内初始值必须是等号形式或者花括号形式。

    7.23 & 7.24

    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    class Screen {
    public:
        using pos = string::size_type;
        // constructors
        Screen() = default;
        Screen(pos ht, pos wd): height(ht), width(wd), contents(ht * wd, ' ') {}
        Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c) {}
        // Member Functions
        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;
        string contents;
    };
    
    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 {
    private:
        vector<Screen> screens{Screen(24, 80, ' ')};
    };
    
    int main()
    {
        Screen myscreen;
        char ch = myscreen.get(); // calls Screen::get()
        ch = myscreen.get(0,0); // calls Screen::get(pos,pos)
        return 0;
    }

    7.25

    可以,Screen类并没有涉及动态内存分配,仅包含基本数据类型、string成员,拷贝、赋值、销毁的默认合成版本可以正常工作。

    7.26

    在原函数的类外定义加上关键字inline即可。 

    【Functions That Return *this】

    // if move returns Screen not Screen&
    Screen temp = myScreen.move(4,0); // the return value would be copied
    temp.set('#'); // the contents inside myScreen would be unchanged

    if move returns Screen&:

    // move the cursor to a given position, and set that character
    myScreen.move(4,0).set('#');

    1、Returning *this from a const Member Function

     A const member function that returns *this as a reference should have a
    return type that is a reference to const

    2、Overloading Based on const 

    class Screen {
    public:
    // display overloaded on whether the object is const or not
    Screen &display(std::ostream &os)
    { do_display(os); return *this; }
    const Screen &display(std::ostream &os) const
    { do_display(os); return *this; }
    private:
    // function to do the work of displaying a Screen
    void do_display(std::ostream &os) const {os <<
    contents;}
    // other members as before
    };

    When we call display on an object, whether that object is const determines which version of display is called:

    Screen myScreen(5,3);
    const Screen blank(5, 3);
    myScreen.set('#').display(cout); // calls non const version
    blank.display(cout); // calls const version

    7.27

    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    class Screen {
    public:
        using pos = string::size_type;
        // constructors
        Screen() = default;
        Screen(pos ht, pos wd): height(ht), width(wd), contents(ht * wd, ' ') {}
        Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c) {}
        // Member Functions
        char get() const { return contents[cursor]; }
        inline char get(pos ht, pos wd) const;
        
        Screen &move(pos r, pos c);
        
        Screen &set(char);
        Screen &set(pos, pos, char);
        
        Screen &display(ostream &os) {
            do_display(os); return *this;
        }
        const Screen &display(ostream &os) const {
            do_display(os); return *this;
        }
    private:
        pos cursor = 0;
        pos height = 0, width = 0;
        string contents;
        
        void do_display(std::ostream &os) const { os << contents; }
    };
    
    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];
    }
    
    inline Screen &Screen::set(char c) {
        contents[cursor] = c;
        return *this;
    }
    
    inline Screen &Screen::set(pos r, pos col, char ch) {
        contents[r*width + col] = ch;
        return *this;
    }
    
    class Window_mgr {
    private:
        vector<Screen> screens{Screen(24, 80, ' ')};
    };
    
    int main()
    {
        // Screen myscreen;
        // char ch = myscreen.get(); // calls Screen::get()
        // ch = myscreen.get(0,0); // calls Screen::get(pos,pos)
        // return 0;
        // Screen myScreen(5, 3);
        // const Screen blank(5, 3);
        // myScreen.set('#').display(cout);
        // blank.display(cout);
        Screen myScreen(5, 5, 'X');
        myScreen.move(4,0).set('#').display(cout);
        cout << '
    ';
        myScreen.display(cout);
        cout << '
    ';
        
        return 0;
    }
    
    // output:
    // XXXXXXXXXXXXXXXXXXXX#XXXX
    // XXXXXXXXXXXXXXXXXXXX#XXXX

    7.28

    move将返回一个副本,对myScreen的后续操作不会被改变myScreen本身,而是myScrenn的副本。

     

    7.29

    XXXXXXXXXXXXXXXXXXXX#XXXX
    XXXXXXXXXXXXXXXXXXXXXXXXX

    7.30

    优点:在某些情况下可以区分成员和参数,例如:this->name = name;相比于f(string name): name(name) {}可以添加一些参数检查。

    缺点:多数情况下是多余的,例如:f(string nm) nm =name;....

    【Class Types】

    一个类的成员类型不能是该类自己。

     7.31

    一个典型的不得不用前置声明的例子。

    class Y; // forward declaration, Y is an incomplete type.
    
    class X {
        Y* pointer;
    };
    
    class Y {
        X object;
    };
    
    int main()
    {
        X x;
        Y y;
        return 0;
    }
  • 相关阅读:
    *关于如何获取指定表的指定字段的数据类型的方法
    *检查表是否存在
    *用Sql添加删除字段,判断字段是否存在的方法
    *MSSQL三个关键系统表
    *系统表的应用
    VC++ ADO编程入门简介
    int i=0; i=i++ System.out.Println(i)
    Microsoft Visual C++ 6.0 关联源代码
    VC ADO接口详解
    程序员每年该做的事
  • 原文地址:https://www.cnblogs.com/xkxf/p/6700751.html
Copyright © 2011-2022 走看看