对于C++中的const关键字来说,主要有以下几类用法:
1、声明一个常量
其使用语法: const <> <> = <>;
示例:
const int TABLE_SIZE = 100;
const char LABLE = 'c';
此外,类型这种内置类型的const常量一样,我们还可以定义const对象。例如 Class A {...}; 则可以 这样定义const 对象 const A a;则此时a为一个const对象,只能调用常量成员函数。
2、常量成员函数
const可以放置到成员函数的参数列表后面,表明这个函数是一个常量成员函数。 常量成员函数可以查看某个对象的状态,但是不能修改其对象。
为什么要使用常量成员函数?
有两个原因:
A、用于提高程序可读性和可靠性,明确声明为常量的成员函数则不会修改对象,若代码中对对象进行了修改,则编译器可以帮助我们进行检查,避免了人为疏忽 造成的错误。
B、让const常量对象可以调用常量成员函数。如果有一个const 对象,则该对象只能调用类中的常量成员函数,不能调用非常量成员函数。 (非const 对象则不受const限制,所以既可以调用非常量成员函数又可以调用常量成员函数。)
另外,要注意的事情: const成员函数中也不能调用非常量成员函数。如果允许const成员函数调用非const成员函数,则会导致const对象在调用const成员函数时间接调用了非const成员函数。
举例如下:
class TestConstFunc
{
public:
TestConstFunc(int val = 0):value(val)
{
}
~TestConstFunc()
{
}
void setValue(int val)
{
value = val;
}
int getValue()const
{
return value;
}
void print()const
{
std::cout << value << std::endl;
}
void print_no_const()
{
std::cout << value << std::endl;
}
private:
int value;
};
void TestConstObject()
{
int x = 0;
TestConstFunc obj;
obj.setValue(4);
x = obj.getValue();
obj.print();
obj.print_no_const();
const TestConstFunc const_obj(10);
//const_obj.setValue(3); //ERROR: setValue 企图修改const对象中的成员数据
//const_obj.print_no_const(); //ERROR: print_no_const 虽然没有企图修改const对象中的成员数据,但是没有const修饰,所以不允许const对象调用。
const_obj.print();
x = const_obj.getValue();
}
在类TestConstFunc中,有一个构造函数和一个析构函数,此外有两个非常量成员函数setValue和print_no_const,两个常量成员函数getValue和print。 当用户在TestConstObject函数中,声明一个非const对象obj时,该对象由于不是const对象,则obj可以调用该类的所有函数。而 const_obj对象由于是一个const对象,则该对象只能调用常量成员函数,调用非常量成员函数则导致编译器错误。(代码中注释的部分)
3、const引用参数
在C++中使用引用作为函数参数主要目的有两个:A、以引用传递的参数可以在函数中修改并传递到被调用函数;B、当参数为用户定义类型时,使用引用作为函数参数传递,可以避免大对象的赋值传递开销。
如果我们使用引用的目的是B项的要求时,一般可以将引用参数声明为const,则避免了在传递的函数内部对传递参数的修改。
例如:
double distance(const point &p1, const point &p2);这样在distance函数内部则不能对p1和p2进行修改,只能读取p1和p2的值,防止由于参数修改影响调用函数。
4、静态成员常量
在类中,静态成员常量的声明前面有两个关键字,分别为static和const。关键字static表明,整个类只有一个该成员的副本,而关键字const则表明程序不能修改这个值(就像普通声明的常量一样)。
例如: static const size_t TABLE_SIZE = 100; 说明了类中的一个表的大小为100。
除了在类定义声明静态成员变量以外,在实现文件中还必须重复这个常量的声明(此时不比使用关键字static)。
例如: const size_t class_name::TABLE_SIZE;
注意:此处的初始值100只能在头文件中(不能再实现文件中)给出。但是,在头文件中定义值的这种技术,只适用于整数类型,比如int或者size_t 。非整数类型则必须采用另外一种方式,把值放到实现文件中,而不能放到头文件中。
例如: 头文件中: static const double d; 实现文件中:const double d = 3.1415;
5、常量迭代器(所指向的对象不能修改)
常量迭代器是一种不以任何方式修改容器的迭代器。它可以再容器中进行移动,但禁止添加、删除或者修改任何数据项。
例如:
#include <vector>
using std::vector;
// 在vector里面找到比target值小的元素个数
vector<int>:: size_type count_less_than_target(const vector<int>& vec, int target)
{
int answer = 0;
vector<int>::const_iterator it; //it 为const常量迭代器,只能在vector容器中移动,不会修改容器数据
for (it = vec.begin(); it != vec.end(); ++it)
{
if (*it < target)
{
++answer;
}
}
return answer;
}
void TestCntLessThanTarget()
{
vector<int> a;
a.push_back(2);
a.push_back(3);
int x = count_less_than_target(a, 4);
std::cout << x << endl; // x=2
}
6、const可以作为指针或者数组参数的修饰符,表示该指针或者数组参数为常量参数
使用类型: fun(const int* i_ptr)
此情况下这些函数可以查看由指针所指向的数据项,但禁止修改数据项。