前言
有了前面的学习基础之后,本文想带大家吃透const关键字在实际开发中的应用。const是不可改变的意思。它可以应用于成员变量、成员函数变量、函数参数、函数返回值等。本文覆盖的场景比较多,能帮大家重新回顾下之前学习的知识点。
const修饰变量
const可以修饰一个变量,表示这个变量是不可修改的,也就是只读的意思。一旦被初始化,该变量的值将不能再被修改。所以说也能表示常量。
const int MAX_VALUE = 100;
// MAX_VALUE的是只读的,它的值不能再被修改
C++表示常量还有另外一种方式。宏定义,格式: #define 常量名 常量值
#define MAX 999
const既可以修饰普通的变量,也可以修饰类的成员变量。初始化const修饰的成员变量有两种方式
1.通过初始化成员列表方式来完成
class MyClass {
private:
const int _count;
public:
MyClass(int value) : _count(value) {}
};
2.在声明常量的同时进行初始化
这种方式被称为直接初始化。这是C++11的新特性。
class MyClass {
private:
//c++11新特性,申明变量时直接初始化
const int COUNT = 100;
public:
MyClass(int value) {}
};
const修饰成员函数
const修饰成员函数,表示该函数不会修改类的成员变量。const关键字加在函数声明的末尾。
class MyClass {
private:
int _data;
public:
MyClass(int value) {}
int getData() const{
// _data++; //这种操作是不被允许的,
return _data;
}
};
加了const之后的函数,该函数中是不能修改该类的任何成员变量。
函数返回值为const
表示返回的是一个常量,不希望返回值被修改。
- 先来看个简单的例子
const int getValue() {
int data = 10;
return data;
}
int main() {
int value = getValue();
value = 20;
}
在这个例子中getValue的返回值是const,它的目的是为了函数的调用者不能修改函数的返回值。但是在函数调用的地方用了一个int类型的变量value来接收函数的返回值,并且又把这个value修改为20。这种情况,对value修改并没有修改函数的返回值。所以说对于函数返回值为基本数据类型,返回值是const没有任何实际意义。
- 再来看一个例子
class A {
public:
int data;
A(int value) : data(value) {}
};
const A getA() {
A a(10);
return a;
}
int main() {
A a2 = getA();
}
上面的getA函数返回值是const修饰的类对象。这个函数用const修饰返回值也是没有意义的。由于返回的对象是一个临时对象,它的生命周期仅限于getA函数的作用域内。因此,即使在调用者尝试修改这个临时对象,也不会对原始对象产生任何影响。
- 再来看一个例子。下面例子返回一个指针数组
char *getValue() {
char *p = new char[10];
strcpy(p, "hello");
return p;
}
int main() {
char *p1 = getValue();
cout << p1 << endl; //输出“hello”
*p1 = 'H'; //修改p1指针指向的内容的第一个字符
cout << p1 << endl; //输出“Hello”
return 0;
}
在这个例子中getValue函数返回值类型是指针数组,在调用该函数的地方用了一个p1指针变量来接收返回值,然后是可以修改修改p1指针的内容的。在这个例子中指针p和p1指向的都是堆内存上的内容,所以说p1修改了内容之后,等于修改了函数的返回值。
要想函数返回值不被修改,可以修改为如下方式
const char *getValue() {
char *p = new char[10];
strcpy(p, "hello");
return p;
}
int main() {
//这样会编译报错,
//error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *'
// char *p1 = getValue();
const char *p1 = getValue();
cout << p1 << endl; //输出“hello”
// *p1 = 'H'; //不支持修改,编译报错
return 0;
}
小结
如果返回的对象是通过值传递的方式返回的,所以即使将返回值声明为const也不会影响调用者对返回值的修改。**只有通过引用或指针返回的对象,使用const修饰才有意义,因为这种情况才会对返回值修改。
函数的参数为const修饰
const关键字可以用于函数参数,表示该参数在函数内部不可被修改。这样可以确保函数不会修改传入的参数值。
class A {
public:
int data;
A(int value) : data(value) {}
};
void func(const A &a){
// a.data = 100; //不支持修改,编译报错
cout << a.data << endl;
}
这一点在之前讲拷贝构造函数的时候已经用到过这个语法了。我们再来回顾下。
class A {
public:
int data;
A(int value) : data(value) {}
//拷贝构造函数
A(const A &a) {
this->data = a.data;
}
};
const修饰对象
这个例子其实和第一个例子是一种类型,只不过它修饰的是类对象。这是一个使用相对不那么广泛的例子,但也需要大家掌握它。
class A {
public:
int data;
A(int value) : data(value) {}
};
int main() {
const A a(10);
// a.data = 100; //编译报错,不能修改任何成员
return 0;
}
这个例子中用const修饰对象A,就不能修改成员变量。
const修饰的对象具有如下特点
- const修饰的对象在声明后其值不能被修改,即为常量对象,而且不能修改任何成员变量。
- const修饰的对象只能访问
const修饰的成员函数,因为访问非const修饰的成员函数极有可能修改成员变量的值。 - const修饰的对象可以访问
public修饰的成员变量,但是不能修改它的值。