effective c++ 學習心得(二)

effective c++ 學習心得(二)

條款03(儘可能使用const)

use const whenever possibleios

引用原文關於const的描述

它容許你指定一個語義約束(也就是制定一個不應被改動的對象,而編譯器會實施這項約束。c++

const的使用範圍

你能夠用它在classes外部修飾global或者namespace做用域的常量或者修飾文件,函數,或
區塊做用域中被聲明爲static對象。你也能夠用它修飾classes內部的static和non-static成員變
量。面對指針,你也能夠指出指針自身,指針所指物,或二者都(或都不)是const函數

例如:
    char greet[] = "Hello";
    char *p1= greet; // non-const pointer, non-const data 指針和指針指向地址的內容均可以改變
    const char *p2 = greet; // non-const pointer, const data 指針的內容能夠改變,指針指向地址的內容不能改變
    char* const p3 = greet; // const pointer, non-const data  指針的內容不能改變,指針指向地址的內容改變
    const char* const p4 = greet; // const pointer, const data  指針的內容不能改變,指針指向地址的內容不能改變
    
    //上面幾個例子展示了const用於指針時的幾種不一樣狀況,在實際狀況下根據本身須要使用。

const在函數中最具威力

const能夠和函數參數,函數返回值,函數自身(成員函數)產生關聯。
舉個例子:學習

#include <iostream>

class Wid{
public:
        void get(int &a){
                if(a = 1){   // 將 == 誤寫成 =
                        std::cout << "in get() the a is " << a << std::endl;
                }
        }
};

int main(){
        Wid w;
        int a = 2;  // a最開始的值是2
        w.get(a);
        std::cout << "the a is " << a << std::endl;
        return 0;
}

運行結果:
    [m@m ~/practice]$ ./7.out
    in get() the a is 1
    the a is 1
    // 從以上結果咱們能夠知道若是咱們在寫代碼時,若是將==誤寫成=,那麼可能就會將一些咱們
    // 不想改變的值給改變,a就是這樣的。

因此有時候const是咱們程序代碼的幫手,能夠幫咱們檢查程序中本不應發生的錯誤。this

// 給int &a 前面加上const,其餘不變,不出意外咱們能夠看到程序報錯的消息
#include <iostream>

class Wid{
public:
        void get(const int &a){
                if(a = 1){
                        std::cout << "in get() the a is " << a << std::endl;
                }
        }
};

int main(){
        Wid w;
        int a = 2;
        w.get(a);
        std::cout << "in main a is " << a << std::endl;

        return 0;
}
運行結果:
    [m@m ~/practice]$ !clang
    clang++ 7.cpp -o 7.out
    7.cpp:6:10: error: cannot assign to variable 'a' with const-qualified type 'const int &'
                            if(a = 1){
                               ~ ^
    7.cpp:5:23: note: variable 'a' declared const here
            void get(const int &a){
1 error generated.


#### const成員函數
const做用於成員函數中時,是不可改變成員變量的,可是全局變量,全局靜態變量,包括還有類中的類靜態成員變量都是能夠
被常成員函數修改的。

爲何說const成員函數比較重要呢?有兩個緣由:
1.它可讓類知道那些函數是能夠修改對象內容(成員變量的,那些是不能夠的。
2.它們是操縱const對象成爲可能。

    // const做用於成員函數中時,是不可改變成員變量的
    #include <iostream>

    class Wid{
    public:
            Wid(int i){
                    a = i;
            }
            void get() const{
                    a++:  // a是成員變量,是不能夠修改的
            }
    private:
            int a;
    };

    int main(){

            Wid w(1);
            w.get();
            return 0;
    }

    運行結果:
        [m@m ~/practice]$ !clang
        clang++ 7.cpp -o 7.out
        7.cpp:9:6: error: cannot assign to non-static data member within const member function 'get'
       a++:
       ~^
        7.cpp:8:8: note: member function 'Wid::get' is declared const here
                void get() const{
                ~~~~~^~~~~~~~~~~
        1 error generated.
        

關於第二點,若是兩個成員函數只是常量性不一樣,能夠被重載,能夠使用const修飾其中一個函數,用來區分重載

    #include <iostream>
    #include <string.h>


    class Wid{
    public:
            Wid(std::string s){
                    text = s;
            }

            char& operator[](std::size_t position){
                    std::cout << "ordinary object" << std::endl;
                    return text[position];
            }

            const char& operator[](std::size_t position) const {
                    std::cout << "const object" << std::endl;
                    return text[position];
            }

    private:
            std::string text;

    };

    int main(){
            Wid w("hello"); // 通常對象
            const Wid w1("world");  // 常對象
            // w[1] = 'x';  //能夠修改
            // w1[2] = 'x';  // 不能夠修改,因爲w1是常對象,調用常函數,返回的是const char &,因此修改它是錯誤的。
            w[1];
            w1[1];
            return 0;

    }
    運行結果:
    ordinary object
    const object
    
    能夠看到兩個重載操做符調用了不一樣的函數。
    
    
隨着繼續學習咱們能夠思考一下是否常函數真的不能修改爲員變量?答案是否認的。
**利用c++中一個與const相關的擺動場:mutable(可變的),能夠實如今常函數中修改爲員變量。**

    #include <iostream>


    class Wid{
    public:
            Wid(int i){
                    a = i;
            }
            void change() const {
                    a++;
                    std::cout << "the a is " << a << std::endl;
            }
    private:
            mutable int a;
    };

    int main(int argc, char *argv[argc])
    {
        Wid w(1);
            w.change();
        return 0;
    }
    
    運行結構:
    the a is 2  // 能夠看到a確確實實被修改了,但沒什麼必要就不要改變常函數的行爲了,容易使代碼出現混亂。
    
#### 在const和non-const成員函數中避免重複
首先貼一段上文的代碼片斷:

        char& operator[](std::size_t position){
                ... // 一些處理代碼
                return text[position];
        }
        const char& operator[](std::size_t position) const {
                ... //同上,相同的處理代碼
                return text[position];
        }
        
咱們能夠看到除了函數名不一樣,函數體的代碼都相同(爲了演示,實際不必定相同),形成了代碼重複,
爲了不這種狀況,咱們能夠使用另一種方法,來實如今一個函數體中調用另外一個函數中的代碼

    #include <iostream>
    #include <string.h>


    class Wid{
    public:
            Wid(std::string s){
                    text = s;
            }

            char& operator[](std::size_t position){
                    // 代碼有兩次轉型,第一次:將*this 從 static_cast<const Wid&> 是爲了將Wid& 轉換爲const Wid&
                    // 第二次: 將返回值類型從const char & 轉換爲char &
                    return const_cast<char&>(static_cast<const Wid&>(*this)[position]); 
            }

            const char& operator[](std::size_t position) const {
                    return text[position];
            }

    private:
            std::string text;

    };

    int main(){
            const Wid w1("world");
            std::cout << "the w1 is " << w1[1] << std::endl;
            return 0;

    }
    
    運行結果:
    the w1 is o


***咱們在non-const函數中調用了const函數來避免了代碼的重複,那是否能夠反向調用,使其在const函數中調用non-const函數呢?
最好不要,由於const函數承諾毫不改變函數的邏輯狀態,而咱們在const函數中調用non-const函數違背了這一準則,由於曾經承
諾的那個對象被修改了***

**總結:**
1.將某些東西聲明爲const,可幫助編譯器檢測出錯誤。const可做用於任何做用域對象,函數參數,函數返回類型,成員函數本體。
2.const和non-const成員函數有着實質的相同實現時,令non-const 調用 const 的版本可避免代碼重複。


有哪些不對的地方,歡迎指正。
相關文章
相關標籤/搜索