C++ const常量成员函数
const的的用法太多了,常量成员函数就是曾经让我迷惑的用法之一,即在成员函数的参数列表之后加上const。
this 指针
在说常量成员函数之前,必须得详细知道this指针,以前我们知道不论C++还是java中,this都可以表示对象本身,事实如此,而在C++中更准确的定义是:
this是一个额外的隐式参数,用来访问当前对象,而它的本质是一个常量指针
常量指针(const pointer),区别于指向常量的指针(const to pointer),前者表示指针的值不能被修改(地址不变),后者表示指针所绑定的对象的值不能被修改,由于this就指向当前对象,我们不能用this在去绑定其他对象,因此他就是一个常量指针。
假设现在有一个类class People
则this的类型是:People *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(22);
cout << p1.getScore() << endl; // error
system("pause");
return 0;
}
这段代码编译器直接报错:
对象包含于成员函数不兼容类型的限定符
这也就说明了普通指针(包括非常量指针和常量指针)无法绑定一个常量对象,这里指的是this指针无法绑定常量对象p1,所以p1无法调用普通的成员函数
那么现在问题又来了,怎么使隐式调用的this指针变成指向常量的常量指针?
答案就是在成员函数的参数列表后面加入关键字const,例如上述示例中:
int getScore() const { return score; }
这样我们就可以使用常量对象调用getScore()
方法了
class people{
public:
//...
int getScore() const{ return score; }
//...
};
int main()
{
const people p1(22);
cout << p1.getScore() << endl; // ok
system("pause");
return 0;
}
这样就叫做常量成员函数(const member function),我们可以使用非常量对象调用常量成员函数,这样做是合法的,因为我们可以使用指向常量的指针来绑定一个非常量对象,例如,下述语句合法:
double pi = 3.14;
const double * ptr = π
关于const成员函数的补充
对于一个成员函数来说,它有一个隐藏的参数,来表示对象的地址,例如:
class Foo
{
public:
void hello(int a)
{
cout << "hello"+a<<endl;
}
};
//...
int main()
{
Foo foo;
int a=2;
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 A
{
//...
public:
// void func1(const A * this);
void func1() const;
// void func2(A * this);
void func2();
}
我们在使用的时候可能有如下组合:
int main()
{
//...
A a1;
const A a2;
a1.func1(); //等价于func1(&a1); //ok
a1.func2(); //等价于func2(&a1); //ok
a2.func1(); //等价于func1(&a2); //ok
a2.func2(); //等价于func2(&a2); //error
}
类比解释:
情况1,用const的指针绑定普通对象,可行,类似于:
int a = 3;
const int *pa = &a;
情况2,用普通指针绑定普通对象,可行,类似于:
int a = 3;
int *pa = &a;
情况3,用const指针绑定常量对象,可行,类似于:
const int a = 3;
const int *pa = &a;
情况4,用普通指针绑定const对象,不可行,类似于:
const int a = 3;
int *pa= &a; // error