T* const 表示不可指向不同的东西 但指向的东西的值可以改变
const T* 表示不可改变指向的东西的值 但可以指向不同的东西
T* const p (const修饰p p为指针 被const修饰后不该被改动 指针p不能改变 但指向的内容*p可被改变)
const T* p (const修饰*p *p为不该被改动的对象)
STL迭代器:
std::vector<int> vec; const std::vector<int>::iterator iter = vec.begin(); //iter的作用像个T* const *iter = 10; //可以实现,改变的是所指物 ++iter; //错误!iter为const std::vector<int>::const_iterator cIter= vec.begin(); //cIter的作用像个const T* *cIter = 10; //错误!*cIter为const cIter++; //可以改变cIter
两个成员函数如果只是常量性(constness)不同,可以被重载。
logical constness,主张一个const成员函数可以修改他所处理的对象内的某些bits,但只有在客户端侦测不出的情况下才得如此。例如CTextBlock class有可能高速缓存(cache)文本区块的长度以便应付询问:
class CTextBlock { public: std::size_t length() const; private: char* pText; std::size_t textLength; //最近一次计算的文本区块长度 bool lengthIsValid; //目前的长度是否有效 }; std::size_t CTextBlock::length() const{ if (!lengthIsValid){ textLength = std::strlen(pText); //错误!在const成员函数内不能赋值 lengthIsValid = true; // 给textLength和lengthIsValid } return textLength; }
解决办法:利用C++的一个与const相关的摆动场:mutable(可变的)。mutable释放掉non-static成员变量的bitwise constness约束:
class CTextBlock { public: std::size_t length() const; private: char* pText; mutable std::size_t textLength; //这些成员变量可能总是会被改变 mutable bool lengthIsValid; //即使在const成员函数内 }; std::size_t CTextBlock::length() const{ if (!lengthIsValid){ textLength = std::strlen(pText); //现在这样就可以了 lengthIsValid = true; // } return textLength; }
class TextBlock{ public: const char& operator[](std::size_t position) const{ //边界检查(bounds checking) //志记数据访问(log access data) //检验数据完整性(verify data integrity) return text[position]; } char& operator[](std::size_t position){ //边界检查(bounds checking) //志记数据访问(log access data) //检验数据完整性(verify data integrity) return text[position]; } private: std::string text; }
以上有代码重复以及伴随的编译时间、维护、代码膨胀等问题。真正该做的是实现operator[]的机能一次并使用它两次。即在其中一个调用另一个。将常量性转除(casting away constness)
class TextBlock{ public: const char& operator[](std::size_t position) const{ //边界检查(bounds checking) //志记数据访问(log access data) //检验数据完整性(verify data integrity) return text[position]; } char& operator[](std::size_t position){ //现在只调用const op[] //边界检查(bounds checking) //志记数据访问(log access data) //检验数据完整性(verify data integrity) return const_cast<char&>( //将op[]返回值的const转除 static_cast<const TextBlock&>(*this) //为*this加上const [position] ); //调用const op[] } private: std::string text; }
这份代码有两个转型动作。在non-const operator[]内部若只是单纯调用operator[],会递归调用自己。所以必须明确的指出调用的是const operator[],但C++缺乏直接的语法可以这样做。因此这里将*this从原始类型TextBlock&转型为const TextBlock&。所以这里有两次转型:第一次用来为*this添加const(这使接下来调用operator[]时得以调用const版本),第二次从const operator[]的返回值中移除const。
反向做法(const成员函数调用non-const成员函数)是错误行为:因为对象有可能因此被改动。