这篇文章记述了关于 C++ const 关键字的知识点。
const
1 | const int& fun(int& a); //修饰返回值 |
如果写的函数需要传入一个指针,面试官可能会问是否需要为该指针加上const,把const加在指针不同的位置是否有区别?(左定值右定向)
如果写的函数需要传入的参数是一个复杂类型的实例,面试官可能会问传入值参数和传入引用参数有什么区别,什么时候需要为传入的引用参数加上const?
- 如果传入的参数不是引用而是实例,那么从形参到实参会调用一次复制构造函数。如果你把复制构造函数的传入参数设置为实例,这样会导致复制构造函数内调用复制构造函数,形成无休止的递归调用从而导致堆栈溢出。同时,如果我们在函数内部不改变传入的实例的状态,应该在传入的引用参数前加上const。

1、const返回值
这种多是修饰返回值是引用类型的情况下,为了避免返回值被修改的情况。
解释下:返回值是引用的函数, 可以肯定的是这个引用必然不是临时对象的引用(栈上的对象在返回后就消失了,自然也就不存在临时对象的引用这么一说了), 因此一定是成员变量或者是函数参数(对象new出来是在堆上,成员变量也在堆上), 所以在返回的时候为了避免其成为左值(下面这个例子很好的说明了什么是左值被修改)被修改,就需要加上const关键字来修饰。
举个例子:
1 |
|
那么这个时候为了避免成员函数被修改就需要加上const关键字,这个时候如果试图改变返回值是不允许的:
1 | error: cannot assign to return value because function 'get_data' returns a const value |
需要指出的是,如果函数的返回类型是内置类型,比如 int char 等,修改返回值本身就是不合法的!所以 const 返回值是处理返回类型为用户定义类型的情况。
2、const 修饰实参
多数情况下,我们都会选择 pass by reference,这样可以节省内存,并且可以起到改变实参的目的。不过有的时候我们并不希望改变实参的值,就要加上const关键字。
这个不仔细说了,很容易理解。不过在构造接口之前一定要思考函数是否会修改参数,如果不会修改的话一定要加上const,这个是代码写的是否大气的一个标准(侯捷大师原话)
3、const 成员函数
首先,面向对象程序设计中,为了体现封装性,通常不允许直接修改类对象的数据成员。
若要修改类对象,应调用公有成员函数来完成。
为了保证const对象的常量性,编译器区分不安全和安全的成员函数(即区分试图修改类对象与不修改类对象的函数),例如:
1 | const Person man; |
在C++中,只有被声明为const的成员函数才能被一个const类对象调用。
要声明一个const类型的类成员函数,只需要在成员函数参数列表后加上关键字const,例如,
1 | class Person{ |
const 修饰成员函数, 根本上是修饰了 this 指针。
在成员函数参数列表后面加上const修饰,表示函数内this指针是一个指向常量对象的指针,不能修改成员变量。
1 | void Person::setName(string name) const |
补充this指针:
每个对象拥有一个this指针,通过this指针来访问自己的地址。this指针并不是对象的一部分,this指针所占的内存大小是不会反应在sizeof操作符上的。
在普通成员函数中,this是一个指向非const对象的const指针(如类类型为Student,那么this就是Student *const类型的指针);
在const成员函数中,this指针是一个指向const对象的const指针(如类类型为Student,那么this就是const Student * const类型的指针)对于const对象或者const对象的引用和指针,对象内的成员变量是不能修改的,因此只能调用const成员函数,不会修改成员变量
对于非const对象,既可以调用const成员函数,也可以调用非const成员函数。
