条款03 尽可能使用const
  NBGtARh4sl8T 2023年11月02日 31 0


const允许指定一个语义约束(也就是指定一个“不该被改动”的对象),而编译器会强制实施这项约束。它允许你告诉编译器和其他程序员某值应该保持不变。


const可以用在classes外部修饰global或者namespace作用域中的常量,或修饰文件、函数、或区块作用域中被声明为static的对象。也可以修饰classes内部的static和non-static成员变量。

char greeting[] = "Hello";
 char *p=greeting;
 const char * p=greeting;//non-const poniter,const data
 char *const p= greeting;//const pointer,non-const data
 const char * const p = greeting;//const pointer,const data



const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在两边,表示被指物和指针两者都是常量。


注意:如果被指物是常量,可以将const写在类型之前,或者在类型之后、星号之前。两种写法意义相同,所以下述两个函数接受的参数类型是一样的。

void f1(const widget *pw);//f1获得一个指针,指向一个常量不变的widget对象
 void f2(widget const *pw);//f2也是



------------------------------------------------------------------------------------------------------------------------

STL迭代器是以指针为根据塑模出来的,所以迭代器的作用就像个T*指针。声明迭代器为const就像声明指针为const一样,表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。


令函数返回一个常量值,往往可以降低因客户错误而造成的意外,而又不至于放弃安全性和高效性。

class Rational{
//....
 };



const Rational operator* (const Rational& lhs,const Rational &rhs);


Rational a,b,c;
(a*b)=c;//在 a*b的成果上调用operator= 



一个良好的用户自定义类型的特征是它们避免无端地域内置类型不兼容(条款18),因此允许对两值乘积做赋值动作也就没什么意思。将operator *的回传值声明为const可以预防那个“没意思的赋值动作”。


---------------------------------------------------------------------------------------------

const成员函数

将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。这类成员函数之所以重要,是因为2个理由。第一,它们使class接口比较容易被理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行。第二,它们使“操作const对象”成为可能。 (这对编写高效代码是个关键,如条款20所示,改善C++程序效率的一个根本办法是以pass by reference to const 方式传递对象,而此技术可行前提是,有const成员函数用来处理取得(并经修饰而成)的const对象)。


两个成员函数如果只是常量性不同,可以被重载。


成员函数如果是const意味着什么?《Effective C++》第三版,P21~P23

bitwise constness认为,成员函数只有在不更改对象之任何成员变量(static除外)时才可以说是const。也就是说它不更改对象内的任何一个bit。bitwise constness正是C++对常量性的定义,因此const成员函数不可以更改对象内任何non-static成员变量。 不幸的是许多成员函数虽然不十足具备const性质却能通过bitwise测试。

一个更改了“指针所指物”的成员函数虽然不能算是const,但如果只有指针(而非其所指物)隶属于对象,那么称此函数未bitwise const不会引发编译器异议。


logical constness认为,一个const成员函数可以修改它所处理的对象内的某些bits,但只有在客户端侦测不出的情况下才得如此。


C++中有一个与const相关的摆动场:mutable(可变的)。mutable释放掉non-static成员变量的bitwise constness约束。


-------------------------------------------------------------------------------------------------------------------------

在const和non-const成员函数中避免重复

对于bitwise constness非我所欲的问题,mutable是个解决办法,但它不能解决所有的const相关难题。如下所示,结束TextBlock内的operator[]不单只是返回一个reference指向某字符,也执行边界检验、日记访问信息、甚至可能进行数据完整性检验。把这些同时放进const和non-const operator[]中,会导致“长度颇为可议”的inline函数。

class TextBlock {
public:
const char & operator[] (std::size_t position) const {
//边界检验
//日志数据访问
//检验数据完整性
return text[position]; 
} 

   char& operator[] (std::size_t position) {
   //边界检验
//日志数据访问
//检验数据完整性
return text[position];  
}


private:
std::string text;
 };



我们应该对上述改进,即实现 operator[]的机能一次并使用它两次。也就是说,你必须令其中一个调用另一个。这促使我们将常量性转移。

class TextBlock {
public:
const char & operator[] (std::size_t position) const {
//边界检验
//日志数据访问
//检验数据完整性
return text[position]; 
} 

   char& operator[] (std::size_t position) {
   
return 
const_cast<char&> (static_cast<const TextBlock&>(*this)[position]); 
}


private:
std::string text;
 };




上述代码有2个转型动作,而不是一个。必须明确指出调用的是const operator[],但是C++缺乏直接的语法可以那样做。因此这里将*this从其原始类型TextBlock&转型为const TextBlock&。使用转型操作为它加上const。所以此处有两次转型,第一次用来为*this添加const(这使接下来调用operator[]时得以调用const版本),第二次则是从const operator[]的返回值中移除const。

添加const的那一次转型强迫进行了一次安全转型(将non-const对象转为const对象),所以我们使用static-cast。移除const的那个动作只可以由const-cast完成,没有其他选择(就技术而言是有的,一个C-style转型也行得通,条款27,但是这种转型很少是正确的选择)。



注意:const成员函数承诺绝不改变其对象的逻辑状态logical state,non-const成员函数却没有这般承诺。在const函数内调用non-const函数,就冒了风险:承诺过不改动的对象被改动了。所以在const成员函数调用non-const成员函数是种错误行为,因为对象有可能因此被改动。实际上若要令这样的代码通过编译,你必须使用一个const_cast将*this身上的const性质解放掉。

non-const成员函数本来就可以对其对象做任何动作,所以在其中调用一个const成员函数并不会带来风险。


------------------------------------------------------------------------------------------------

将某些东西声明为const可帮助编译器侦测出错误的用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。

编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”。

当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

NBGtARh4sl8T