你很德布罗意的技术博客

C++ Const关键字用法总结

用法 例子 说明
const变量 const int a; 不能改变值,必须初始化
const类变量 const MyClass a; 不能修改成员变量,不能调用非const函数
指向const变量的指针 const int * a; 不能修改指向的内容,可以改变指向的对象
const指针 int * const a; 可以修改指向的内容,不能改变指向的对象
指向const变量的const指针 const int * const a; 不能修改指向的内容,也不能改变指向的对象
const引用
const变量作为函数参数 void MyMethod(const int a); 函数体内不能修改其值,若是指向const变量的指针做参数,上层可通过一般指针调用
const返回值 const int & MyMethod(); 返回const引用,上层不能通过此引用修改对象
const成员变量 const int * a;
static const int * a;
- 非静态的const成员变量必须在初始化列表里初始化,之后不能改变其值
- 静态的const成员变量需要单独定义和初始化,不能在初始化列表里初始化
const成员函数 void MyMethod() const; 函数体内的this指针为指向const对象的const指针,不能修改非mutable成员变量

下面用代码来测试一遍这些特性,看会有什么发现

1. Const变量

test.cpp
1
2
3
4
5
6
7
8
# include <iostream>
using namespace std;

const int a;
int main()
{

}

这里顺带说明一下Mac下快速调试C++的方法,写好cpp文件后,只需执行编译命令g++ -o test ./test.cpp,就会在当前目录下生成可执行文件test,再用命令行运行即可。

这时编译会报错 default initialization of an object of const type ‘const int’
这是因为const变量必须要初始化,把const int a;改成const int a = 1;即可编译成功。

2. Const类变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# include <iostream>
using namespace std;

class A{
public:
A(){};
int prop;
void test()
{
cout << "invoke test()" << endl;
};
};

int main()
{
const A a;
a.prop = 1;
a.test();
}
  • 上述代码不能编译通过,因为const类变量不能修改成员变量,a.prop = 1;这一句会提示
    error: cannot assign to variable ‘a’ with const-qualified type ‘const A’

  • a.test()会提示
    error: ‘this’ argument to member function ‘test’ has type ‘const A’, but function is not marked const
    因为test成员函数没有const限定符,不能被const类对象a调用,将test成员函数加上const限定符
    void test() const即可编译通过。

3. 指向const变量的指针

1
2
3
4
5
6
7
8
9
10
11
# include <iostream>
using namespace std;

int main()
{
int value1 = 5;
int value2 = 10;
const int * a = &value1;
a = &value2;
*a = 20;
}
  • a是指向const变量的指针,初始化时赋值为整型数value1的地址,其指向的对象是可以改变的,所以可以将a重新指向value2的地址
  • 但其指向地址的内容不能改变,所以不能通过a将value2的值修改,*a = 20;编译报错error: read-only variable is not assignable

4. Const指针

1
2
3
4
5
6
7
8
9
10
11
12
13
# include <iostream>
using namespace std;

int main()
{
int value1 = 5;
int value2 = 10;
int * const a = &value1;

*a = 20;
cout << "value1=" << value1 << endl;
a = &value2;
}
  • a是const指针,不可以修改其指向,所以在初始化时把a指向value1之后不能再指向value2,a = &value2;编译报错error: cannot assign to variable ‘a’ with const-qualified type ‘int *const’
  • const指针可以修改其指向地址的内容,所以可以把a指向的内容改成20,同时从输出可以看到value1的值也改成了20,因为*a和value1实际上是同一个值对象

5. 指向const变量的const指针

1
2
3
4
5
6
7
8
9
10
11
12
# include <iostream>
using namespace std;

int main()
{
int value1 = 5;
int value2 = 10;
const int * const a = &value1;

*a = 20;
a = &value2;
}

这个其实是等于指向const变量的指针和Const指针的组合,因为其指向的对象和内容都不能修改,所以代码最后的两处赋值语句都会编译报错

  • *a = 20;报错 error: read-only variable is not assignable
  • a = &value2; 报错 error: cannot assign to variable ‘a’ with const-qualified type ‘const int *const’

6. Const变量作为函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# include <iostream>
using namespace std;

class A {
public:
void test1(const int a)
{
// a = 10;
// cout << "test1: " << a << endl;
};
void test2(const int * a)
{
cout << "test2" << endl;
};
};

int main()
{
int value = 5;
int * pValue = &value;
A a;
a.test1(value);
a.test2(pValue);
}

代码在类A中有两个测试函数,分别测试const变量和指向const变量的指针做函数参数时的情况

  • test1函数无法通过编译,因为试图修改const变量a,这其实是和函数外修改const变量一样是禁止的,a = 10;编译报错 error: cannot assign to variable ‘a’ with const-qualified type ‘const int’
  • 去掉test1相关代码编译运行输出test2,说明test2用指向const变量的指针作参数时,上层可以通过一般指针调用

7. Const返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# include <iostream>
using namespace std;

class A {
public:
A():m_str(""){};
const std::string & getStr()
{
return m_str;
};

private:
std::string m_str;
};

int main()
{
A a;
const std::string & str1 = a.getStr();
str1 = "test";
}

代码中的类A有私有成员m_str,通过公有方法getStr()获取私有成员并尝试赋值。
代码会编译报错,在Mac下为 error: no viable overloaded ‘=’,因为尝试给const引用赋值而其赋值运算符没有可用的重载方法,即返回的const引用是不可以修改的。

8. Const成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# include <iostream>
using namespace std;

class A {
public:
const int value1;
static const int value2 = 0;
A(){};
};

int main()
{

}
  • 代码中类A定义了一个const变量value1,一个静态const变量value2,const变量必须在构造函数的初始化列表里进行初始化,否则会报错 error: constructor for ‘A’ must explicitly initialize the const member ‘value1’
  • 若将构造函数改为A():value2(0){};,则会报错 error: member initializer ‘value2’ does not name a non-static data member or base class,说明在初始化列表里初始化的变量必须为非静态的,静态的成员变量必须单独定义和初始化

9. Const成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# include <iostream>
using namespace std;

class A {
public:
void test() const{
value = 0;
};
private:
mutable int value;
};

int main()
{
A a;
a.test();
}

代码中类A定义了一个私有的mutable变量,和一个const成员函数test(),因为const成员函数体内可以正常修改带有mutable修饰的成员变量,代码正常运行。如果将成员变量的mutable去掉,编译报错 error: cannot assign to non-static data member within const member function ‘test’, 说明Const成员函数无法修改非mutable的成员变量。


专题:

本文发表于 2020-10-10,最后修改于 2020-10-19。

本站永久域名www.namidame.tech,也可搜索「 你很德布罗意的技术博客 」找到我。

欢迎关注我的 微博 ,查看最近的文章和动态。


上一篇 « C++数组指针和指针数组的区别 下一篇 » Hexo Geektutu主题Gitalk初始化位置

赞赏支持

客官,打赏一个呗~

i ali

支付宝

i wechat

微信

推荐阅读

Big Image