const告诉编译器它所约束的对象是不允许被修改的,它可以作用于任何作用域类的对象(包括类对象),函数参数和返回值,及成员函数本体,使用它可以在编译时及时发现错误。
1)const与指针
const可以修饰指针本身,也可以修饰指针所指的对象,或者限制指针与其所指对象都为const,如下:
const char* p = "hello";//non-const pointer, const data
char* const p = "hello"; //const pointer, non-const data
const char* const p = "hello"; //const pointer, const data
注意,const限制指针所指物不可修改时,有以下两种方式:
const char* p = "hello";
char const * p = "hello";
也就是说,const既可以位于数据类型前也可以位于数据类型后,但必须位于星号前,它们组合在一起用来修饰指针所指的对象。可以这样理解,星号前面的用来修饰被指物,星号
后面的用来修饰指针。
2)const与STL迭代器
STL迭代器与指针类似(难道不是一样的吗?),用const修饰迭代器就像声明指针为const一样,表示该迭代器不能指向不同的东西,如果要限制迭代器所指的对象不可修改,则需
要使用const_iterator,具体如下:
std::vector<int> v;
...
const std::vector<int>::iterator<int> iter = v.begin(); // iter是不能更改的,类似T* const
*iter++; //ok!
iter++; //error, iter是const常量
std::vector<int>::const_iterator<int> iter = v.beign(); //iter不是const,所指对象是const,不能更改
*iter++; //error!
iter++; //ok!
3)const修饰函数参数及返回值
对于函数声明:
const int operator*(const int& a, const int& b)
{
return a*b;
}
它表示函数的参数和返回值都是不可以被修改的,所以下面的代码就是错误的:
int a = 3;
int b = 4;
int c = 5;
a*b = c; //a*b返回的是一个const常量,不可以修改
4)const与成员函数
a. 被const修饰的成员函数使得操作“const对象”成为可能,例如下面的代码编译就无法通过:
1 class Head
2 {
3 public:
4 Head(string s) { pText = s; }
5 char& operator[](size_t pos)
6 {
7 return pText[pos];
8 }
9 private:
10 string pText;
11 }
12
13 int main()
14 {
15 const Head h1("Hello");
16 cout<<h1[1]<<endl; //成员函数operator[]不能操作const对象
17 }
此时可以添加const成员函数来操作const对象:
const char& operator[](std::size_t pos) const { return pText[pos]; }
b. 被const修饰的成员函数不改动任何非static成员变量,下面的情况除外:成员变量是一个指针类型,此时指针所指的地址不可以改变,但指针所指的对象却可以改变。比如将
上面代码中的成员变量pText改为char*类型,即声明如下:
char* pText;
同时令对应的const成员函数的返回值不再是const类型,具体修改如下:
char& operator[](std::size_t pos) const { return pText[pos]; }
那么下面const成员函数调用也是正确的:
const Head h2("Good");
char* p = &h2[0];
*p = 'J'; //此时pText所指向的字符串为“Jood”
这样的情况编译器能够通过是因为在const成员函数确实没有改变成员变量pText的值,只是改变了该值对应的变量。如果执意要在const成员函数中对成员变量进行赋值操作,那
么可以引入摆动场:mutable,它将释放在const成员函数中非static成员变量的不可改动性。
例如如下代码将通过编译:
1 class Head
2 {
3 public:
4 ...
5 size_t length() const;
6
7 private:
8 char* pText;
9 mutable size_t textLength; //表示这些变量可能经常会被改动,即使在
10 mutable bool LengthIsValid; //const成员函数里也有可能被修改
11 };
12
13 size_t Head::length()
14 {
15 if(!LengthIsValid)
16 {
17 textLength = strlen(pText);
18 LengthIsValid = true;
19 }
20 }
5)const转型
如果两个重载函数只是在是否是常量性上有区别,要做的事几乎一样,那么可以通过将常量性转除来实现调用两次却只执行一次的功能,这样一来就避免了代码的重复,从而减
少编译时间,代码维护时间以及避免代码膨胀等问题。因为const成员函数的本意是不修改对象,而non-const成员函数却可以对对象做任意的修改,所以在const成员函数中调用
non-const是不合理也是不允许的,但是在non-const成员函数中调用const成员函数却是可行的,具体如下:
1 class Head
2 {
3 public:
4 ...
5 const char& operator[](std::size_t pos) const
6 {
7 return pText[pos];
8 }
9 char& operator[](std::size_t pos)
10 {
11 return const_cast<char&>(static_cast<const Head&>(*this)[pos]);
12 }
13 }
上述代码中有两次转型操作,首先通过static_cast<constHead&>将类型为Head&的*this转为const Head&类型,从而调用const的成员函数,然后通过const_cast
切记:const成员函数不可以调用non-const成员函数。
原文链接: https://www.cnblogs.com/sophia-yun/archive/2013/05/03/3057280.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/86905
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!