effective c++ 学习心得(二)
条款03(尽量使用const)
use const whenever possible
引用原文关于const的描述
它允许你指定一个语义约束(也就是制定一个不该被改动的对象,而编译器会实施这项约束。
const的使用范围
你可以用它在classes外部修饰global或者namespace作用域的常量或者修饰文件,函数,或
区块作用域中被声明为static对象。你也可以用它修饰classes内部的static和non-static成员变
量。面对指针,你也可以指出指针自身,指针所指物,或两者都(或都不)是const
例如:
char greet[] = "Hello";
char *p1= greet; // non-const pointer, non-const data 指针和指针指向地址的内容都可以改变
const char *p2 = greet; // non-const pointer, const data 指针的内容可以改变,指针指向地址的内容不能改变
char* const p3 = greet; // const pointer, non-const data 指针的内容不能改变,指针指向地址的内容改变
const char* const p4 = greet; // const pointer, const data 指针的内容不能改变,指针指向地址的内容不能改变
//上面几个例子展现了const用于指针时的几种不同情况,在实际情况下根据自己需要使用。
const在函数中最具威力
const可以和函数参数,函数返回值,函数自身(成员函数)产生关联。
举个例子:
#include <iostream>
class Wid{
public:
void get(int &a){
if(a = 1){ // 将 == 误写成 =
std::cout << "in get() the a is " << a << std::endl;
}
}
};
int main(){
Wid w;
int a = 2; // a最开始的值是2
w.get(a);
std::cout << "the a is " << a << std::endl;
return 0;
}
运行结果:
[m@m ~/practice]$ ./7.out
in get() the a is 1
the a is 1
// 从以上结果我们可以知道如果我们在写代码时,如果将==误写成=,那么可能就会将一些我们
// 不想改变的值给改变,a就是这样的。
所以有时候const是我们程序代码的帮手,可以帮我们检查程序中本不该发生的错误。
// 给int &a 前面加上const,其他不变,不出意外我们可以看到程序报错的消息
#include <iostream>
class Wid{
public:
void get(const int &a){
if(a = 1){
std::cout << "in get() the a is " << a << std::endl;
}
}
};
int main(){
Wid w;
int a = 2;
w.get(a);
std::cout << "in main a is " << a << std::endl;
return 0;
}
运行结果:
[m@m ~/practice]$ !clang
clang++ 7.cpp -o 7.out
7.cpp:6:10: error: cannot assign to variable 'a' with const-qualified type 'const int &'
if(a = 1){
~ ^
7.cpp:5:23: note: variable 'a' declared const here
void get(const int &a){
1 error generated.
#### const成员函数
const作用于成员函数中时,是不可改变成员变量的,但是全局变量,全局静态变量,包括还有类中的类静态成员变量都是可以
被常成员函数修改的。
为什么说const成员函数比较重要呢?有两个原因:
1.它可以让类知道那些函数是可以修改对象内容(成员变量的,那些是不可以的。
2.它们是操纵const对象成为可能。
// const作用于成员函数中时,是不可改变成员变量的
#include <iostream>
class Wid{
public:
Wid(int i){
a = i;
}
void get() const{
a++: // a是成员变量,是不可以修改的
}
private:
int a;
};
int main(){
Wid w(1);
w.get();
return 0;
}
运行结果:
[m@m ~/practice]$ !clang
clang++ 7.cpp -o 7.out
7.cpp:9:6: error: cannot assign to non-static data member within const member function 'get'
a++:
~^
7.cpp:8:8: note: member function 'Wid::get' is declared const here
void get() const{
~~~~~^~~~~~~~~~~
1 error generated.
关于第二点,如果两个成员函数只是常量性不同,可以被重载,可以使用const修饰其中一个函数,用来区分重载
#include <iostream>
#include <string.h>
class Wid{
public:
Wid(std::string s){
text = s;
}
char& operator[](std::size_t position){
std::cout << "ordinary object" << std::endl;
return text[position];
}
const char& operator[](std::size_t position) const {
std::cout << "const object" << std::endl;
return text[position];
}
private:
std::string text;
};
int main(){
Wid w("hello"); // 一般对象
const Wid w1("world"); // 常对象
// w[1] = 'x'; //可以修改
// w1[2] = 'x'; // 不可以修改,由于w1是常对象,调用常函数,返回的是const char &,所以修改它是错误的。
w[1];
w1[1];
return 0;
}
运行结果:
ordinary object
const object
可以看到两个重载操作符调用了不同的函数。
随着继续学习我们可以思考一下是否常函数真的不能修改成员变量?答案是否定的。
**利用c++中一个与const相关的摆动场:mutable(可变的),可以实现在常函数中修改成员变量。**
#include <iostream>
class Wid{
public:
Wid(int i){
a = i;
}
void change() const {
a++;
std::cout << "the a is " << a << std::endl;
}
private:
mutable int a;
};
int main(int argc, char *argv[argc])
{
Wid w(1);
w.change();
return 0;
}
运行结构:
the a is 2 // 可以看到a确确实实被修改了,但没什么必要就不要改变常函数的行为了,容易使代码出现混乱。
#### 在const和non-const成员函数中避免重复
首先贴一段上文的代码片段:
char& operator[](std::size_t position){
... // 一些处理代码
return text[position];
}
const char& operator[](std::size_t position) const {
... //同上,相同的处理代码
return text[position];
}
我们可以看到除了函数名不同,函数体的代码都相同(为了演示,实际不一定相同),造成了代码重复,
为了避免这种情况,我们可以使用另外一种方法,来实现在一个函数体中调用另一个函数中的代码
#include <iostream>
#include <string.h>
class Wid{
public:
Wid(std::string s){
text = s;
}
char& operator[](std::size_t position){
// 代码有两次转型,第一次:将*this 从 static_cast<const Wid&> 是为了将Wid& 转换为const Wid&
// 第二次: 将返回值类型从const char & 转换为char &
return const_cast<char&>(static_cast<const Wid&>(*this)[position]);
}
const char& operator[](std::size_t position) const {
return text[position];
}
private:
std::string text;
};
int main(){
const Wid w1("world");
std::cout << "the w1 is " << w1[1] << std::endl;
return 0;
}
运行结果:
the w1 is o
***我们在non-const函数中调用了const函数来避免了代码的重复,那是否可以反向调用,使其在const函数中调用non-const函数呢?
最好不要,因为const函数承诺绝不改变函数的逻辑状态,而我们在const函数中调用non-const函数违背了这一准则,因为曾经承
诺的那个对象被修改了***
**总结:**
1.将某些东西声明为const,可帮助编译器检测出错误。const可作用于任何作用域对象,函数参数,函数返回类型,成员函数本体。
2.const和non-const成员函数有着实质的相同实现时,令non-const 调用 const 的版本可避免代码重复。
有哪些不对的地方,欢迎指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。