天天看点

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