《Effective C++》条款3:const问题
本章节主要讲解了const的一些应用问题,并且通过例子系统的讲解了const的使用场景和方法;
针对于指针和函数来说:
首先注意的是变量、指针和函数返回时使用const修饰时的场景;
char greeting[] = "hello"; const char* a=greeting; char* const b=greeting;
如上的例子,分别有const char* 和 char* const两种形式;
这里给出一个判断法则:对于指针const修饰,指针是const还是数据是const,由星号*和const的位置而定;
如果const在*左边,则指代指针为const;
如果const在*右边,则指代指针指向数据为const;
其中值得注意的是,如果采用容器中的iterator作为指针模拟,则最好使用const_iterator,防止引起混淆;
如果使用const iterator(),则代表该迭代器指针是const,不得指向别的对象;
如果使用const_iteraotr(),则代表该迭代器指向的数据是const,不得修改;
对于函数来说,除了const 引用,比较少见的是返回值const;
返回值const通常常见于类内的重载运算符函数上;
例如:
class ration { const ration operator*(const ration& a, const ration& b); };
初次见可能不太明白加上const的意义是什么;
其实考虑一下if((a*b)=c),其中a,b,c都为ration类,所以可以看到,根据运算结果,存在错误赋值的情况;
所以使用const返回可以有效地避免相关错误的出现;
针对于类内成员函数来说:
对于常见的成员函数,有两种典型的const使用:
1.声明该成员函数为const;
2.传参或者返回值为const,一般为reference-to-const或者pointer-to-const;
其中针对于成员函数是否为const,可以进行重载;
#include<iostream> #include<string> using namespace std; class test { private: string s; public: test(string a) :s(a) {}; const char& operator[](std::size_t position) { cout << "this is non-const version" << endl; return s[position]; } const char& operator[](std::size_t position) const{ cout << "this is const version" << endl; return s[position]; } }; int main() { const test a("123"); test b("123"); a[0]; b[0]; system("pause"); return 0; }
从上述[]运算符可以看出来,类内对于[]进行了重载;
对于const类,会调用const版本的重载函数,非const类调用普通版本的重载函数;
对于const函数(也就是函数后是否加上const),本质上取决于是否想通过该函数对相关的涉及内容进行修改;
关于const的看法,书中提到了两派:
1.bitwise-constness流派:const函数不能进行更改数据的操作;
2.logical-constness流派:const函数可以修改数据,但是不能让编译器发现;
其实现行编译器依据的规则就是第一派,但是可以使用其他关键字和方法实现第二派的思想;
例如,如果对const函数中进行赋值,则有以下的报错信息:
从而说明编译器现阶段const函数仍然以不能显式修改操作为主;
对于第二流派,可以显式使用mutable关键字进行修改,这样可以在const函数中进行修改;
存在问题:
对于不同const对象实现重载,可能会导致代码膨胀等后果,导致维护工作上升;
所以常见的方法是使用转型调用,即进行const和non-const的互相调用;
常见的操作时进行调用,使用const版本来进行函数主体实现;
non-const进行const版本的调用,但是需要进行const和non-const的类型转换;
如下所示:
class test { private: mutable string s; public: test(string a) :s(a) {}; char& operator[](std::size_t position) { return const_cast<char&>(static_cast<const test&>(*this)[position]); } const char& operator[](std::size_t position) const{ return s[position]; } };
上述代码进行了两次类型转换:
1.将non-const test对象转化为const test对象,使用static_cast进行转型;
2.使用const_cast对const的返回值进行去const处理;
通过上述两步操作可以使用const函数为non-const函数进行操作服务,从而无需大段的进行复制;
但是注意一点:不能通过const调用non-const,因为non-const不能保障是否进行修改操作,从而不能使安全性得到保证;
个人存在疑惑:
1.关于const的相关应用场景;
2.关于转型问题的补充;
3.关于*this的详细的调用场景;