美文网首页
条款03: 尽可能使用const

条款03: 尽可能使用const

作者: 未来已来_1cab | 来源:发表于2019-01-25 16:50 被阅读0次

    标准C范畴下的尽可能使用const

    面对指针,你可以指出指针自身、指针所指物,或两者都(或都不)是const:

    char greeting[] = "Hello";
    char* p = greeting;                //non-const pointer, non-const data
    const char* p = greeting;      //non-const pointer, const data
    char* const p = greeting;      //const pointer, non-const data
    const char* const p = greeting;  //const pointer, const data
    

    如果被指物是常量,可以写做:

    void f1(const Widget* pw);
    

    令函数返回一个常量值,往往可以降低客户错误而造成的意外,而又不至于放弃安全性和高效性。举个例子,考虑有理数的operator*声明式:

    //写法一:类外写法
    const Rational operator* (const Rational& lhs, const Rational& rhs);
    

    许多程序员第一次看到这个声明时不免斜着眼睛说,唔,为什么返回一个const对象?原因是如果不这样客户就能实现这样的暴行:

    Rational a, b, c;
    ...
    if(a * b = c)    //喔欧,其实是想做一个比较动作!
    {...}
    

    将operator*的回传值声明为const可以预防那个“没意思的赋值动作”,这就是该那么做的原因。

    STL范畴下的尽可能使用const

    STL迭代器系以指针为根据塑模出来,所以迭代器的作用就像个T*指针。声明迭代器为const就像声明指针为const一样(即声明一个T* const指针),表示这个迭代器不得指向不同的东西,但它所指的值是可以改动的。如果你希望迭代器所指的东西不可被改动(即希望STL模拟一个const T*指针),你需要的是const_iterator:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main()
    {
            vector<int> vec(10, 1);
            // iter acts like a T* const
            const vector<int>::iterator iter = vec.begin();
            // OK, changes what iter points to
            *iter = 10; 
            //++iter; // error! iter is const
            //cIter acts like a const T*
            vector<int>::const_iterator cIter = vec.begin();
            //*cIter = 10; // error! *cIter is const
            ++cIter; // fine, changes cIter
    
            return 0;
    }
    

    Object Oriented C++范畴的尽可能使用const

    将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。

    #include <iostream>
    #include <string>
    using namespace std;
    
    class TextBlock
    {
    public:
        TextBlock() : text("")
        {
        }
        TextBlock(const char t[]) : text(t)
        {
        }
        TextBlock(const TextBlock& tb) : text(tb.text)
        {
        }
        ~TextBlock(){}
        //写法二:类内写法
        const char& operator[](size_t position)const
        {
            return text[position];
        }
        char& operator[](size_t position)
        {
            cout << text << endl;
            text = "ByeBye";
            return text[position];
        }
    private:
        string text;
    };
    
    int main(int argc, char* argv[])
    {
        TextBlock tb("Hello");
        cout << tb[0] << endl;     //call non-const TextBlock::operator[]
        tb[0] = 'x';
        cout << tb[0] << endl;
        const TextBlock ctb("World");
        cout << ctb[0] << endl;   //call const TextBlock::operator[]
        /* 下面错误只因operator[]的返回类型以致,至于operator[]调用动作自身没问
         * 题。错误起因于企图对一个“由const版之operator[]返回”的const char&施行赋
         * 值动作。
         */
    //  ctb[0] = 'x';
    
        return 0;
    }
    

    成员函数怎么才是真正的const的呢?

    bitwise const阵营的人相信,成员函数只有在不更改对象之任何成员变量(static除外)时可以说是const。不幸的是许多成员函数虽然不十足具备const性质却能通过bitwise测试。

    #include<iostream>
    #include<string>
    using namespace std;
    
    class CTextBlock {
    public:
        CTextBlock(const char t[]) : text(t)
        {
            pText = &text[0];
        }
        //inappropriate (but bitwise const) declaration of operator[]
        char& operator[](size_t position)const
        {
            return pText[position];
        }
        int putstring()const
        {
            cout << text << endl;
            return 0;
        }
    private:
        string text;
        char *pText;
    };
    
    int main()
    {
        const CTextBlock cctb("Hello"); // declare constant object
        //call the const operator[] to get a pointer to cctb's data
        char *pc = &cctb[0];
        cout << *pc << endl;
        *pc = 'J'; // cctb now has the value "Jello"
        cout << cctb[0] << endl;
        cctb.putstring();
        return 0;
    }
    

    logical constness一派主张,一个const成员函数可以修改它所处理的对象内的某些bits(下面例子即是此主张的技术上的处理技巧),但只有在客户端侦测不出的情况下才得如此,比如下面的例子,一个TextBlock的长度在逻辑上就应该是一个常量,所以求长度的函数设计为const函数。

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    class CTextBlock {
    public:
        size_t length() const;
    private:
        char *pText;
        //these data members may
        mutable size_t textLength;
        //always be modified, even in const member functions
        mutable bool lengthIsValid;
    };
    size_t CTextBlock::length() const
    {
        if (!lengthIsValid) {
            textLength = strlen(pText); // now fine
            lengthIsValid = true; // also fine
        }
        return textLength;
    }
    
    int main()
    {
        return 0;
    }
    

    对于“bitwise-constness非我所欲”的问题,mutable是个解决办法,但它不能解决所有的const相关难题。比如:

    在const和non-const成员函数中通过互相调用避免重复

    #include<iostream>
    #include<string>
    using namespace std;
    
    class TextBlock {
    public:
        TextBlock(const char t[]) :text(t)
        {};
        const char& operator[](size_t position) const // same as before
        {
            return text[position];
        }
        char& operator[](size_t position) // now just calls const op[]
        {
            return
                /* cast away const on op[]'s return type; call const version of op[]
                 */
                const_cast<char&>(
                /* We cast *this from its native type of TextBlock& to const TextBlock&.
                 * In order to call const op[]
                 */
                        static_cast<const TextBlock&>(*this)[position]);
        }
    private:
        string text;
    };
    
    int main()
    {
        TextBlock ctb("Hello");
        cout << ctb[0] << endl;
    
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:条款03: 尽可能使用const

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