《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的详细的调用场景;

posted @ 2020-12-02 18:13  暮云林凌  阅读(127)  评论(0)    收藏  举报