C++中const的用法详解

来源:互联网 发布:bp网络和神经网络区别 编辑:程序博客网 时间:2024/05/01 01:05

你也许有常量的概念并会用关键字const声明一个变量为常量,但是你知道const除了声明常量外,还可以声明const指针和const成员函数。本文将讨论const对象是如何建立、const对象的用途以及他们的语法。

Const声明

仅仅用一个关键字就可以声明三种截然不同的结构,所以const声明常常让人混淆。让我们仔细看看这些这三种不同的const结构。

Const对象
当你把某个对象定义为const类型(在这里“对象”一词用的是它的广义语义,例如保存一个变量或者类对象的一段内存)之前,你需要确保程序不会再修改它。Const声明必须包括合适的初始化。代码清单A中包含有不同const对象的实例。

Const指针
如果把一个指针定义为const类型,那么程序就不能再让它指向一个新的地址。不过const指针所指向的对象仍可以修改,如代码清单B所示。

Const成员函数
一个类对象的状态由它的非静态数据成员组成。类中不需要修改对象状态的成员函数应该定义为const类型。你可以在类的成员函数的参数表后面加上关键字const来声明它为const函数。例如:

class Person{public:
int getAge() const {return age;} //const成员函数
private: int age;};

注意const成员函数是约束语法设计(the Design by Contract idiom)的一个重要的组成部分。Const成员函数确保了编程者承诺要实现的功能(如,保持对象的状态不变)由编译器强制实现。任何试图从内部修改const成员变量以及非const成员变量的举动都会导致编译时错误的产生:

int Person::getAge() const{
return ++age; //编译时出错
}
另外,const声明可以证明函数的行为。
混合类型

到目前为止,一切似乎都没有问题。然而,声明混合类型时麻烦不期而至。你能在下面的例子中分辨出x和y是哪一种类型么?

const char * x= “hello”;
char const * y= “world”;

x和y的类型是一样的,即“指向const类型字符串的指针”——虽然const出现在x和y的位置上。关键字const可以出现在它声明的变量的类型名(字)的前面或者后面,这不会影响到声明的意义——这与下面例子中的关键字long和unsigned很相似:

int long x;
long int y;
unsigned long l;
long unsigned m;

现在,让我们看看下面这个const声明:

char * const z= “world”;

这里,z的类型是“指向非const类型字符串的const型指针”。编译器是如何知道变量z是const指针而x和y不是呢?

--------------------------------------------------------------------------------
const指针和指向const变量的指针的区别是什么?
通过检查关键字出现在const星号之前还是之后,你可以区分const指针和const变量。“* const”声明一个const指针,与之相反,当const出现在星号之前,指针指向的对象是const类型的。
--------------------------------------------------------------------------------

指向const对象的const指针
你可以在单个声明中把const对象和const指针联在一起,即声明指向const对象的const指针。例如:


const int n=10;
const int * const p= & n; // 指向const int对象的const指针

因为p的声明中出现了“* const”,所以p是const型指针。p指向一个const型的整数,因在它的声明中,关键字const出现在星号之前。在通过有固定地址的内存缓冲来访问ROM设备的情况下,指向const对象的const指针的用法就特别有用。

现在,你也许正在想“我是不是可以在单个的声明语句中把三种const结构联在一起?”,答案是肯定的。在下面的例子中,我们定义一个返回一个指向const整数的const指针的const成员函数:



class A{
//…
const int * const get_scores(int id) const;
};


运算符const_cast<>
const_cast<>运算符用来消除对象的const属性。不过,使用这个运算符还有几个限制,我们将简单的讨论这些限制。

消除const属性
尽管const_cast<>可以消除一个对象的const属性,但这并不意味着你就可以修改该对象。考虑下面的例子:

const char * p= “hello world”;int main() {
char * s = const_cast (p); // 消除const属性
strcpy(s, “danger!”); // 不可以,不明确的状态
}

试图重写字符串s将会导致不明确的状态。其原因是const对象可能保存在系统的只读内存中。如果你强制去除一个对象的const属性可以把该对象当着非const对象使用(例如,把它传递给一个接受char *类型参数的函数),但不能修改它。

非const型到const型的转换
绝大多数程序员不知道const_cast<>也有相反的操作,也就是说,它可以把一个非const型的对象转换为const型对象。例如:


char s[]= “fasten your seatbelt”;
size=strlen(const_cast (s));// 更明确

但是你可以看到使用const_cast<>h的机会很少,原因是C++在需要使用const型对象的环境下会自动执行非const型到const型的转换。因此,你不会真正需要这样使用const_cast<>,除非你想验证你的代码。

结论
const在语法上的障碍常常使得编程者放弃使用它,这就削弱了编程质量和产生的代码的可读性以及可维护性。诚然,指向const对象的指针和const指针的区分不应该这么容易混淆——尤其是在处理混合类型时;不过,通过检查const限定词相对星号的位置可以消除上述的模糊性,并且,const成员函数很容易辨识(const出现在参数表后)。如果你对const感到头痛的话,相信通过本文,你会发现const的妙用。

原创粉丝点击