标准C范畴下的尽可能使用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);
令函数返回一个常量值,往往可以降低客户错误而造成的意外,而又不至于放弃安全性和高效性。举个例子,考虑有理数的operator*声明式:
//写法一:类外写法
const Rational operator* (const Rational& lhs, const Rational& rhs);
许多程序员第一次看到这个声明时不免斜着眼睛说,唔,为什么返回一个const对象?原因是如果不这样客户就能实现这样的暴行:
Rational a, b, c;
...
if(a * b = c) //喔欧,其实是想做一个比较动作!
{...}
将operator*的回传值声明为const可以预防那个“没意思的赋值动作”,这就是该那么做的原因。
STL范畴下的尽可能使用const
STL迭代器系以指针为根据塑模出来,所以迭代器的作用就像个T*指针。声明迭代器为const就像声明指针为const一样(即声明一个T* const指针),表示这个迭代器不得指向不同的东西,但它所指的值是可以改动的。如果你希望迭代器所指的东西不可被改动(即希望STL模拟一个const T*指针),你需要的是const_iterator:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec(10, 1);
// iter acts like a T* const
const vector<int>::iterator iter = vec.begin();
// OK, changes what iter points to
*iter = 10;
//++iter; // error! iter is const
//cIter acts like a const T*
vector<int>::const_iterator cIter = vec.begin();
//*cIter = 10; // error! *cIter is const
++cIter; // fine, changes cIter
return 0;
}
Object Oriented C++范畴的尽可能使用const
将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。
#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[](size_t position)const
{
return text[position];
}
char& operator[](size_t position)
{
cout << text << endl;
text = "ByeBye";
return text[position];
}
private:
string text;
};
int main(int argc, char* argv[])
{
TextBlock tb("Hello");
cout << tb[0] << endl; //call non-const TextBlock::operator[]
tb[0] = 'x';
cout << tb[0] << endl;
const TextBlock ctb("World");
cout << ctb[0] << endl; //call const TextBlock::operator[]
/* 下面错误只因operator[]的返回类型以致,至于operator[]调用动作自身没问
* 题。错误起因于企图对一个“由const版之operator[]返回”的const char&施行赋
* 值动作。
*/
// ctb[0] = 'x';
return 0;
}
成员函数怎么才是真正的const的呢?
bitwise const阵营的人相信,成员函数只有在不更改对象之任何成员变量(static除外)时可以说是const。不幸的是许多成员函数虽然不十足具备const性质却能通过bitwise测试。
#include<iostream>
#include<string>
using namespace std;
class CTextBlock {
public:
CTextBlock(const char t[]) : text(t)
{
pText = &text[0];
}
//inappropriate (but bitwise const) declaration of operator[]
char& operator[](size_t position)const
{
return pText[position];
}
int putstring()const
{
cout << text << endl;
return 0;
}
private:
string text;
char *pText;
};
int main()
{
const CTextBlock cctb("Hello"); // declare constant object
//call the const operator[] to get a pointer to cctb's data
char *pc = &cctb[0];
cout << *pc << endl;
*pc = 'J'; // cctb now has the value "Jello"
cout << cctb[0] << endl;
cctb.putstring();
return 0;
}
logical constness一派主张,一个const成员函数可以修改它所处理的对象内的某些bits(下面例子即是此主张的技术上的处理技巧),但只有在客户端侦测不出的情况下才得如此,比如下面的例子,一个TextBlock的长度在逻辑上就应该是一个常量,所以求长度的函数设计为const函数。
#include <iostream>
#include <cstring>
using namespace std;
class CTextBlock {
public:
size_t length() const;
private:
char *pText;
//these data members may
mutable size_t textLength;
//always be modified, even in const member functions
mutable bool lengthIsValid;
};
size_t CTextBlock::length() const
{
if (!lengthIsValid) {
textLength = strlen(pText); // now fine
lengthIsValid = true; // also fine
}
return textLength;
}
int main()
{
return 0;
}
对于“bitwise-constness非我所欲”的问题,mutable是个解决办法,但它不能解决所有的const相关难题。比如:
在const和non-const成员函数中通过互相调用避免重复
#include<iostream>
#include<string>
using namespace std;
class TextBlock {
public:
TextBlock(const char t[]) :text(t)
{};
const char& operator[](size_t position) const // same as before
{
return text[position];
}
char& operator[](size_t position) // now just calls const op[]
{
return
/* cast away const on op[]'s return type; call const version of op[]
*/
const_cast<char&>(
/* We cast *this from its native type of TextBlock& to const TextBlock&.
* In order to call const op[]
*/
static_cast<const TextBlock&>(*this)[position]);
}
private:
string text;
};
int main()
{
TextBlock ctb("Hello");
cout << ctb[0] << endl;
return 0;
}