你也许有常量的概念并会用关键字const声明一个变量为常量,但是你知道const除了声明常量外,还可以声明const指针和const成员函数。本文将讨论const对象是如何建立、const对象的用途以及他们的语法。
Const声明
仅仅用一个关键字就可以声明三种截然不同的结构,所以const声明常常让人混淆。让我们仔细看看这些这三种不同的const结构。
Const对象
当你把某个对象定义为const类型(在这里“对象”一词用的是它的广义语义,例如保存一个变量或者类对象的一段内存)之前,你需要确保程序不会再修改它
。Const声明必须包括合适的初始化
。代码清单A中包含有不同const对象的实例。
Listing A
const int MAX_FILES=15;
const std::string ip_address=“202.180.109.89”;
const char message[14]=“please rewind”;
const double inch2cm = 2.54;
Const指针
如果把一个指针定义为const类型,那么程序就不能再让它指向一个新的地址
。不过const指针所指向的对象仍可以修改
,如代码清单B所示。
Listing B
int n=10, m=0;
int *const pci = &n; // pci is a const pointer to int
pci++; // error, trying to modify a const pointer
pci= &m; // also an error
*pci=9; //OK
Const成员函数
一个类对象的状态由它的非静态数据成员组成
。类中不需要修改对象状态的成员函数应该定义为const类型
。你可以在类的成员函数的参数表后面加上关键字const来声明它为const函数。例如:
class Person{public:
int getAge() const {return age;} //const成员函数
private: int age;};
注意const成员函数是约束语法设计的一个重要的组成部分。Const成员函数确保了编程者承诺要实现的功能(如,保持对象的状态不变)由编译器强制实现。任何试图从内部修改const成员的举动都会导致编译时错误的产生:
int Person::getAge() const
{ return ++age; } //编译时出错.类中修改了age
int Person::getAge() const
{ int temp = age + 1;
return temp;
} //实现方法.
另外,const声明可以证明函数的行为。
类的const数据成员
const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员
,因为类的对象未被创建时,编译器不知道const数据成员的值是什么。const数据成员的初始化只能在类的构造函数的初始化表中进行
。如下:
class Person
{ private:
int age;
public:
Person();
};
Person::Person()
{ const int age = 5;
}
修饰函数参数的const
如 void fun0(const A* a ); void fun1(const A& a);
调
用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A*
a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A&
a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。参数const通常用于参数为指针或引用的情况,且只能修饰输入参数;若输入参数采用“值
传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。
因此。对于非内部数据类型的输入参
数,应该将“值传递”的方式改为“const引用传递”,目的是为了提高效率。例如,将void Func(A a)改为void
Func(const A &a)
。对于内部数据类型(基本数据类型如int,char,double等)的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提
高效率的目的,又降低了函数的可理解性。例如void Func(int x)不应该改为void Func(const int &x)
混合类型
下面的例子中x和y是哪一种类型?
const char * x= “hello”;
char const * y= “world”;
x和y的类型是一样的,即“指向const类型字符串的指针”——虽然const出现在x和y的位置上。关键字const可以出现在它声明的变量的名字的前面或者后面,这不会影响到声明的意义.
现在,让我们看看这个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_cast<>运算符用来消除对象的const属性。不过,使用这个运算符还有几个限制,我们将简单的讨论这些限制。 例子中,我们定义一个返回一个指向const整数的const指针的const成员函数:
class A
{ //…
const int * const get_scores(int id) const;
};
消除const属性
尽管const_cast<>可以消除一个对象的const属性,但这并不意味着你就可以修改该对象。考虑下面的例子:
const char * p= “hello world”;int main() {
char * s = const_cast <char *> (p); // 消除const属性
strcpy(s, “danger!”); // 不可以,不明确的状态
}
试图重写字符串s将会导致不明确的状态。其原因是const对象可能保存在系统的只读内存中。如果你强制去除一个对象的const属性可以把该对象当着非const对象使用(例如,把它传递给一个接受char *类型参数的函数),但不能修改它。
对类内的数据进行修改,但是我们的接口却被声明了const。
此时的标准用法:mutable
class A
{ public:
A(int i=0):test(i) {}
void SetValue(int i)const { test=i; }
private:
mutable int test; //若无mutable 则无法修改。
};
int main()
{ const A tt(90);
tt.SetValue(20);
return 0;
}
非const型到const型的转换
const_cast<>也有相反的操作,也就是说,它可以把一个非const型的对象转换为const型对象。例如:
char s[]= “fasten your seatbelt”;
size=strlen(const_cast<const char *> (s));// 更明确
但是你可以看到使用const_cast<>的机会很少,原因是C++在需要使用const型对象的环境下会自动执行非const型到const型的转换。因此,你不会真正需要这样使用const_cast<>,除非你想验证你的代码。
结论
const在语法上的障碍常常使得编程者放弃使用它,这就削弱了编程质量和产生的代码的可读性以及可维护性。诚然,指向const
对象的指针和const指针的区分不应该这么容易混淆——尤其是在处理混合类型时;不过,通过检查const限定词相对星号的位置可以消除上述的模糊性,
并且,const成员函数很容易辨识(const出现在参数表后)。如果你对const感到头痛的话,相信通过本文,你会发现const的妙用。
本文详细介绍了C++中const关键字的多种用途,包括const对象、const指针及const成员函数的定义与使用,同时解释了const_cast的正确用法。

被折叠的 条评论
为什么被折叠?



