天天看點

C++ const常量成員函數C++ const常量成員函數

C++ const常量成員函數

const的的用法太多了,常量成員函數就是曾經讓我迷惑的用法之一,即在成員函數的參數清單之後加上const。

this 指針

在說常量成員函數之前,必須得詳細知道this指針,以前我們知道不論C++還是java中,this都可以表示對象本身,事實如此,而在C++中更準确的定義是:

this是一個額外的隐式參數,用來通路目前對象,而它的本質是一個常量指針

常量指針(const pointer),差別于指向常量的指針(const to pointer),前者表示指針的值不能被修改(位址不變),後者表示指針所綁定的對象的值不能被修改,由于this就指向目前對象,我們不能用this在去綁定其他對象,是以他就是一個常量指針。

假設現在有一個類

class people

則this的類型是:

people *const

const成員函數

那麼現在問題來了,const成員函數究竟是什麼玩意?

上面提到,this指針是一個非常量版本的常量指針,那麼當我們建立常量對象的時候,不能把this綁定到一個常量對象上——即不能使用一個常量對象調用普通函數。

代碼:

class people{
public:
    people(){}
    people(int x) :score(x){}
    ~people(){}
    int getScore(){ return score; }
private:
    int score;
};
int main()
{
    const people p1();
    cout << p1.getScore() << endl;//error
    system("pause");
    return ;
}
           

這段代碼編譯器直接報錯:

對象包含于成員函數不相容類型的限定符。

這也就說明了普通指針(包括非常量指針和常量指針)無法綁定一個常量對象。簡單來講,下述語句無法成立:

const double pi=;
double* ptr1=&pi;//error1
double* const ptr2=&pi;//error2
const double* ptr1=&pi;//ok1
const double* const ptr2=&pi;//ok2
           

我們需要用一個指向常量的指針來綁定常量對象。

那麼現在問題又來了,怎麼使隐式調用的this指針變成指向常量的常量指針?

答案就是在成員函數的參數清單後面加入關鍵字const,例如上述示例中:

int getScore() const { return score; }
           

這樣我們就可以使用常量對象調用

getScore()

方法了

class people{
public:
    //...
    int getScore() const{ return score; }
    //...
};
int main()
{
    const people p1();
    cout << p1.getScore() << endl;//ok
    system("pause");
    return ;
}
           

這樣就叫做常量成員函數(const member function),我們可以使用非常量對象調用常量成員函數,這樣做是合法的,因為我們可以使用指向常量的指針來綁定一個非常量對象,例如,下述語句合法:

double pi = ;
const double * ptr=&pi;
           

是以,下述使用也是合法:

class people{
public:
    //...
    int getScore() const{ return score; }
    //...
};
int main()
{
    people p2();
    cout << p2.getScore() << endl;//ok
    //...
}
           

—————–2016年5月29号更新—————–

關于const成員函數的補充

對于一個成員函數來說,它有一個隐藏的參數,來表示對象的位址,例如:

class Foo
{
public:
    void hello(int a)
    {
        cout << "hello"+a<<endl;
    }
};
//...
int main()
{
    Foo foo;
    int a=;
    foo.hello(a);
    //等價于
    foo.hello(&foo,a);
}
           

從上述代碼看出,這裡相當于有一個該對象位址的隐式參數傳遞,也就是說,從函數聲明的角度,這裡應該是這個樣子:

class Foo
{
public:
    void hello(Foo* this ,int a)
    {
        cout << "hello"+a<<endl;
    }
};
           

當我們給成員函數的聲明後面加上const以後,例如:

void hello(int a) const
{
    cout << "hello"+a<<endl;
}
           

這裡就可以了解為有一個const的指針作為參數,如

void hello(const Foo * this,int a) const
{
    cout << "hello"+a<<endl;
}
           

因為this是const的類型的,當然也就防止了成員函數對類中成員進行修改。

知道了這個東西,就能正确引導我們的使用。

比如說,假如有一個class

class A
{
//...
public:
    void func1() const;
    void func2();
}
           

我們在使用的時候可能有如下組合:

int main()
{
//...
    A a1;
    const a2;
    a1.func1();
    //等價于a1.func1(&a1);//ok

    a1.func2();
    //等價于a1.func2(&a1);//ok

    a2.func1();
    //等價于a2.func1(&a2);//ok

    a2.func2();
    //等價于a2.func2(&a2);//error
}
           

情況1,用const的指針綁定普通對象,可行,類似于:

int a =;
const int *pa=&a;
           

情況2,用普通指針綁定普通對象,可行,類似于:

int a=;
int *pa=&a;
           

情況3,用const指針綁定常量對象,可行,類似于:

const int a =;
const int *pa=&a;
           

情況4,用普通指針綁定const對象,不可行,類似于:

const int a =;
int *pa= &a;//error
           

參考:http://stackoverflow.com/questions/3141087/what-is-meant-with-const-at-end-of-function-declaration