1. const关键字
const可以修饰的对象分类
如,
char greeting[] = "Hello";
char* p = greeting; //non-const pointer, non-const data
const char* p = greeting; //non-const pointer, const data
char* const p = greeting; //const pointer, non-const data
Const char* const p = greeting; //const pointer, const data
判断规则:
另外,
void f1(const Widget* pw); //f1获得一个指针,指向一个不变的Widget对象
void f2(Widget const * pw); //f2 is the same as f1
2. STL迭代器与const
STL迭代器的作用像T*指针
声明迭代器为const就像声明指针为const一样,即声明一个T* const指针,表明迭代器不能指向不同的东西,但所指的东西的值可变;
若希望迭代器所指的东西不可改变,即希望STL模拟一个const T*指针,则需要const_iterator;
如:
std::vector<int> vec;
...
const std::vector<int>::iterator iter = vec.begin(); //iter即T* const指针,指针本身不可变
*iter = 10; //ok
++iter; //error, because iter is const
Std::vector<int>::const_iterator citer = vec.begin(); //citer即const T*指针,指针所指物不可变
*citer = 10; //error, because *citer is const
++citer; //ok
3. 函数与const
(1) 修饰函数的返回值
另函数返回一个常量值,可以降低因客户错误造成的意外。
如:
class Rational{...};
const Rational operator*(const Rational& lhs, const Rational& rhs);
Rational a, b, c;
...
(a * b) = c; //在a*b的成果上调用operator=,对函数的返回值在进行赋值无意义
//如果a,b都是内置类型,编译不通过
//此处编译也不通过,因为operator*的返回值为const,不可变,对其进行赋值当然不允许
if (a * b = c)//实际上是'==',却意外写成了'=',如果operator*函数的返回值声明为const,这类错误即可在编译期间被发现
如果函数的返回类型是个内置类型,那么改动函数返回值从来就不合法。
(2) const参数
防止在函数内对该参数进行修改。如想要键入'==',却意外键成'=',这类的错误会在编译期间被发现。
(3) const成员函数
两个成员函数如果只是常量性(constness)不同,可以被重载。
小结:
Source code
/************************************************************************
Description:
Item 3: Use const whenever possible.
book, page 21
************************************************************************/
#include <iostream>
#include <string>
using namespace std;
class TextBlock
{
public:
TextBlock(): text("")
{
}
TextBlock(const char t[]): text(t)
{
}
TextBlock(const TextBlock& tb): text(tb.text)
{
}
~TextBlock(){}
const char& operator[](std::size_t position) const
{
return text[position];
}
char& operator[](std::size_t position)
{
return text[position];
}
private:
std::string text;
};
int main(int argc, char* argv[])
{
TextBlock tb("Hello");
std::cout << tb[0]; //call non-const TextBlock::operator[]
const TextBlock ctb("World");
std::cout << ctb[0] << endl; //call const TextBlock::operator[]
return 0;
}
debug
# gdb ./item3
GNU gdb Red Hat Linux (6.6-35.fc8rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) b 44
Breakpoint 1 at 0x8048898: file item3.cpp, line 44.
(gdb) r
Starting program: /home/zubo/effectivecpp/item3
warning: Missing the separate debug info file: /usr/lib/debug/.build-id/ac/2eeb206486bb7315d6ac4cd64de0cb50838ff6.debug
warning: Missing the separate debug info file: /usr/lib/debug/.build-id/88/27308433e33aeefb560f42fb133577c8936f20.debug
warning: Missing the separate debug info file: /usr/lib/debug/.build-id/92/8ab51a53627c59877a85dd9afecc1619ca866c.debug
warning: Missing the separate debug info file: /usr/lib/debug/.build-id/db/8cb95645d5df469d4aece301cdb5e60087be21.debug
warning: Missing the separate debug info file: /usr/lib/debug/.build-id/ba/4ea1118691c826426e9410cafb798f25cefad5.debug
Breakpoint 1, main () at item3.cpp:44
44 TextBlock tb("Hello");
(gdb) step
TextBlock (this=0xbfd566cc, t=0x8048b00 "Hello") at item3.cpp:18
18 TextBlock(const char t[]): text(t)
(gdb)
20 }
(gdb)
20 }
(gdb)
main () at item3.cpp:45
45 std::cout << tb[0]; //call non-const TextBlock::operator[]
(gdb)
TextBlock::operator[] (this=0xbfd566cc, position=0) at item3.cpp:35
35 return text[position];
(gdb)
36 }
(gdb)
main () at item3.cpp:47
47 const TextBlock ctb("World");
(gdb)
TextBlock (this=0xbfd566c8, t=0x8048b06 "World") at item3.cpp:18
18 TextBlock(const char t[]): text(t)
(gdb)
20 }
(gdb)
20 }
(gdb)
main () at item3.cpp:48
48 std::cout << ctb[0] << endl; //call const TextBlock::operator[]
(gdb)
TextBlock::operator[] (this=0xbfd566c8, position=0) at item3.cpp:30
30 return text[position];
(gdb) set print pretty
(gdb) p *this
$1 = {
text = {
static npos = 4294967295,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Alloc_hider:
_M_p = 0x85c602c "World"
}
}
}
(gdb) c
Continuing.
HW
Program exited normally.
(gdb) q
成员函数如果是const意味着什么?
两个流派:
观点:成员函数只有在不更改对象之任何成员变量(static除外)时才可以说是const,即不更改对象内的任何一个bit。
Bitwise constness正是C++对常量性的定义,因此const成员函数不可以更改对象内任何non-static成员变量。
(4) 在const和non-const成员函数中避免重复
例如,operator[]函数,
你真正应该做的是实现operator[]的机能一次而使用它两次。即必须令其中一个调用另一个。这就是常量性转除(casting away constness)。
本例中const operator[]完全做掉了non-const版本应该做的一切,唯一的不同就是其返回类型多了一个const资格修饰,这种情况下如果将返回值的const转除是安全的,因为不能谁调用non-const operator[],都一定首先有个non-const对象,否则不能调用non-const对象。所以令non-const operator[]调用其const兄弟是一个避免代码重复的安全做法——即使过程中需要一个转型动作。
小结:
4. 总结
const可以用在
Remember