C++ const 修饰符

Posted 我是小白呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ const 修饰符相关的知识,希望对你有一定的参考价值。

概述

const 是 constant 的缩写, 是不变的意思. 在 C++ 中是用来修饰内置类型变量, 自定义对象, 成员函数, 返回值, 函数参数. const 可以帮我们避免无意之中的错误操作.
在这里插入图片描述
使用 const, 把有关的数据定义为常量 (常变量 / 常对象 / 常函数). const 既可以使数据在一定范围内共享, 又要保证它不被任意修改.

const 包括:

  • 常对象
  • 常指针
  • 常引用

常对象

我们可以将需要保证数据成员不改变的对象, 可以声明为常对象. 常对象中的所有成员的值都不能被修改.

常变量的两种格式:

类名 const 对象名[(实参表列)];
const 类名 对象名[(实参表列)];

常对象必须要有初始值. 例如:

Time const t1(12, 34, 46);
const Time t1(12, 34, 46);

试图改变常对象的成员值会发生什么:

int main() {

    const Time t1(10, 10, 10);  // 定义const Time对象
    t1.set_time(2,2,2);  // 试图改变t1对象的成员数据, 报错

    return 0;
}

输出:
C:\\Users\\Windows\\CLionProjects\\Project1\\main.cpp: In function 'int main()':
C:\\Users\\Windows\\CLionProjects\\Project1\\main.cpp:10:22: error: passing 'const Time' as 'this' argument discards qualifiers [-fpermissive]
     t1.set_time(2,2,2);
                      ^
In file included from C:\\Users\\Windows\\CLionProjects\\Project1\\main.cpp:2:
C:\\Users\\Windows\\CLionProjects\\Project1\\Time.h:12:10: note:   in call to 'void Time::set_time(int, int, int)'
     void set_time(int h, int m=0, int s=0);
          ^~~~~~~~
mingw32-make.exe[3]: *** [CMakeFiles\\Project1.dir\\build.make:81: CMakeFiles/Project1.dir/main.cpp.obj] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\\Makefile2:94: CMakeFiles/Project1.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\\Makefile2:101: CMakeFiles/Project1.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:136: Project1] Error 2

常对象成员

常成员函数

如果我们要引用常对象中的数据成员, 就需要将该成员函数声明为 const 型函数, 即常成员函数. 常成员函数可以访问对象中的数据成员, 但不允许修改常对象中数据成员的值.

举个栗子:

Time 类:

#ifndef PROJECT1_TIME_H
#define PROJECT1_TIME_H

class Time {
private:
    int minute;
    int second;
public:
    int hour;
    Time();  // 默认构造函数
    Time(int h, int m=0, int s=0);  // 有参构造函数
    void set_time(int h, int m=0, int s=0);
    void show_time() const;  // 声明为常成员函数
};

#endif //PROJECT1_TIME_H

Time.cpp:

#include "Time.h"
#include <iostream>
using namespace std;

// 默认构造函数
Time::Time() : hour(0), minute(0), second(0) {}

// 有参构造函数
Time::Time(int h, int m, int s) : hour(h), minute(m), second(s) {}

void Time::set_time(int h, int m, int s) {
    hour = h;
    minute = m;
    second = s;
}

void Time::show_time() const {
    cout << hour << ":" << minute << ":" << second << endl;
}

main:

#include "Time.h"
#include <iostream>
using namespace std;

int main() {

    const Time t1(10, 10, 10);  // 定义const Time对象
    t1.show_time();  // 调用常成员函数

    return 0;
}

调试输出:

10:10:10

注: const 是函数类型的一部分, 在声明函数和定义函数时都要有 const 关键字.

常数据成员

当我们用关键字 const 来声明常量数据成员, 可以限定其值不能改变.

Time 类:

#ifndef PROJECT1_TIME_H
#define PROJECT1_TIME_H

class Time {
private:

public:
    const int hour;  // 定义hour为常数据成员
    int minute;
    int second;

    Time();  // 默认构造函数
    Time(int h, int m=0, int s=0);  // 有参构造函数
    void set_time(int m=0, int s=0);
    void show_time() const;  // 声明为常成员函数
};

#endif //PROJECT1_TIME_H

因为 hour 为常数据成员, 所以我们只能通过构造函数的参数初始化表对常数据成员进行初始化.

// 默认构造函数
Time::Time() : hour(0), minute(0), second(0) {}

// 有参构造函数
Time::Time(int h, int m, int s) : hour(h), minute(m), second(s) {}

我们不能再构造函数中用赋值的方法对常数据成员初始化. 例如:

Time::Time(int h){hour=h;}  // 非法

不能用成员函数改变常数据成员的值. 例如:

void Time::setHour(int h){hour=h;}  // 非法

数据成员访问限制

常对象中的成员函数未加 const, 编译系统认为其是非 const 成员函数.
在这里插入图片描述

常对象修改的限制

如果一个对象被声明为常对象, 则不能调用该对象的非 const 型的成员函数, 除了由系统自动调用的隐式的构造函数和析构函数.

要点:

  • 编辑系统只检查函数的声明, 只要发现调用了常对象的成员函数, 而该函数未被声明为 const, 就报错
  • 防止函数修改常对象中数据成员的值
  • 编译系统对不安全的因素予以拦截, 为我们开发人员省了不少心
  • 用常成员函数引用常变量

常指针

将指针变量声明为 const 型, 指针值始终保持为其初始值, 不能改变.

指向对象的常指针格式:

类名 *const 变量名;
Time time1(10, 12, 15), t2;
Time * const pt = &t1  // pt 是常指针
pt = &t2; // 将一个指针固定

常见用途: 将一个指针固定地与一个对象联系. 将常指针作为函数的形参, 目的是不允许在函数执行过程中改变指针变量的值.

void doSomething(Test * const p1){
    p1 -> setX(5);
    p1 -> printxy();
} 

指向常变量的指针

定义指向常变量的指针变量的一般形式为:

const 类名 *变量名 / 类型名 const *变量名;

只有常变量的指针能指向常变量:
在这里插入图片描述
指向常变量的指针变量可以指向未被声明为 const 的变量, 但不能通过此指针变量改变该变量的值.
在这里插入图片描述
重点:

  • 如果一个变量已被声明为常变量 / 对象. 我们就只能用指向常变量的指针指向他, 而不能用非 const 型的变量 / 对象的指针去指向它.

指向对象的指针

定义指向对象的指针变量的一般形式为.

const 类名 *变量名 / 类名 const *变量名;

举个栗子:
在这里插入图片描述
如果一个对象已经被声明为常对象, 我们就只能用指向常对象的指针指向他. 而不能用指向非 const 型变量 / 对象的指针指向他.

指向常对象的指针变量可以指向未被声明为 const 的对象, 但不能通过此指针来改变该对象的值. 例如:
在这里插入图片描述

小结

指向常对象的指针最常用语函数的形参, 以保护形参指针所指向的对象在函数执行过程中不被修改.

当我们希望在调用函数时对象的值不被修改, 就应当把形参定义为指向常对象的指针变量. 同时用对象的地址作为实参 (对象可以是 const 或非 const 型).
在这里插入图片描述
在这里插入图片描述

对象的常引用

一个变量的应用就是变量的别名. 变量名和引用名都指向同一段没存单元.

函数的形参可以是对象的引用. 如果不希望在函数中修改实参的值, 可以将形参声明为常引用. 例如:

void fun(Time &t); 
void fun(const Time &);  // 常引用

我们应该尽量使用常引用作为函数参数, 原因有二:

  1. 既能保证数据安全, 使数据不能被随意修改
  2. 在调用函数时不必建立实参的copy, 可以提高程序运行效率

总结

在这里插入图片描述

以上是关于C++ const 修饰符的主要内容,如果未能解决你的问题,请参考以下文章

C++ const 修饰符

C++ const修饰符的简单介绍

C++ --- C++函数后面加const修饰符

[Reprint]C++函数前和函数后加const修饰符区别

为啥这个函子的 operator() 需要尾随 const 修饰符?

《c++ const 详细总结》--转载