C++中const修饰成员函数

一、const 成员函数的核心定义

const修饰成员函数时,要写在函数参数列表后、函数体前(有virtual则在virtual后),其核心作用是:保证该成员函数不会修改当前对象的任何非静态成员变量,且只能调用其他 const 成员函数。

语法格式:

cpp 复制代码
// 声明(类内)
返回值类型 函数名(参数列表) const;

// 定义(类外)
返回值类型 类名::函数名(参数列表) const {
    // 函数体
}

二、为什么需要 const 成员函数?

核心目的是保证 "常量对象" 的只读性------ 当一个对象被声明为const(常量对象)时,编译器要求它只能调用const成员函数,防止对象被意外修改。

先看一个没有 const 成员函数的反例:

cpp 复制代码
#include <iostream>
using namespace std;

class Person {
public:
    int age = 20;

    // 普通成员函数:可修改成员变量
    void showAge() {
        cout << "Age: " << age << endl;
        // 即使没修改,编译器也认为这个函数"可能修改"对象
    }
};

int main() {
    // 常量对象:不允许被修改
    const Person p;
    p.showAge(); // 编译报错!常量对象不能调用普通成员函数

    return 0;
}

报错原因:编译器无法确定showAge()是否会修改p,因此禁止常量对象调用普通成员函数 ------ 而const成员函数就是用来告诉编译器:"这个函数绝对不会修改对象,放心让常量对象调用"。

三、const 成员函数的使用规则(核心)

  1. 基础规则:const 成员函数不能修改非静态成员变量
cpp 复制代码
#include <iostream>
using namespace std;

class Person {
public:
    int age = 20;
    static int total = 0; // 静态成员变量

    // const成员函数:只读,不能修改非静态成员
    void showAge() const {
        cout << "Age: " << age << endl; // 允许:仅读取
        // age = 30; // 编译报错!const函数不能修改非静态成员变量

        total = 100; // 允许:静态成员变量不属于具体对象,不受const限制
    }

    // 普通成员函数:可读写
    void setAge(int a) {
        age = a; // 允许修改
    }
};

int main() {
    // 1. 常量对象:只能调用const成员函数
    const Person p1;
    p1.showAge(); // 正常执行
    // p1.setAge(30); // 编译报错!常量对象不能调用普通成员函数

    // 2. 普通对象:既可以调用const成员函数,也可以调用普通成员函数
    Person p2;
    p2.showAge(); // 正常执行
    p2.setAge(30); // 正常执行

    return 0;
}
  1. 进阶规则:const 成员函数只能调用其他 const 成员函数
cpp 复制代码
class Person {
public:
    int age = 20;

    void func1() const {
        func2(); // 编译报错!const函数不能调用普通成员函数
        func3(); // 允许:调用其他const成员函数
    }

    void func2() {
        // 普通成员函数
    }

    void func3() const {
        // const成员函数
    }
};

原因:普通成员函数 "可能修改对象",而 const 成员函数承诺 "不修改对象",因此不能调用有修改风险的普通成员函数。

  1. 例外:mutable 成员变量可被 const 函数修改

mutable(可变的)修饰的成员变量,突破 const 的限制 ------ 即使在 const 成员函数中,也能修改mutable成员(用于存储 "逻辑上不影响对象常量性" 的状态,比如缓存、计数):

cpp 复制代码
#include <iostream>
using namespace std;

class Person {
public:
    int age = 20;
    mutable int visitCount = 0; // 可变成员:记录访问次数

    void showAge() const {
        visitCount++; // 允许:mutable成员可被const函数修改
        cout << "Age: " << age << ",访问次数:" << visitCount << endl;
    }
};

int main() {
    const Person p;
    p.showAge(); // 输出:Age: 20,访问次数:1
    p.showAge(); // 输出:Age: 20,访问次数:2
    return 0;
}

四、底层原理:const 修饰的是 this 指针

const 成员函数的本质,是修改了this指针的类型:

普通成员函数中,this的类型是:类类型* const(指针本身不可改,指向的对象可改);

const 成员函数中,this的类型是:const 类类型* const(指针本身不可改,指向的对象也不可改)。

编译器视角的伪代码对比:

cpp 复制代码
// 普通成员函数:void showAge(Person* const this)
void Person::showAge() {
    this->age = 30; // 允许:this指向的对象可改
}

// const成员函数:void showAge(const Person* const this)
void Person::showAge() const {
    this->age = 30; // 报错:this指向的对象是const,不可改
}

核心:const成员函数的this指针是 "指向 const 对象的 const 指针",因此无法通过this修改成员变量 ------ 这也是 const 函数不能修改非静态成员的底层原因。

五、const 成员函数的重载

const 成员函数可以和普通成员函数构成重载,编译器会根据调用对象是否为 const,选择对应的版本:

cpp 复制代码
#include <iostream>
using namespace std;

class Person {
public:
    int age = 20;

    // 普通版本:供普通对象调用
    void showAge() {
        cout << "普通版本:Age = " << age << endl;
    }

    // const版本:供常量对象调用
    void showAge() const {
        cout << "const版本:Age = " << age << endl;
    }
};

int main() {
    Person p1; // 普通对象
    p1.showAge(); // 调用普通版本

    const Person p2; // 常量对象
    p2.showAge(); // 调用const版本

    return 0;
}

总结

核心作用:const 成员函数承诺 "不修改对象的非静态成员变量",让常量对象可以安全调用;

关键规则:

不能修改非静态成员变量(mutable成员除外);

只能调用其他 const 成员函数;

可与普通成员函数构成重载,编译器根据对象是否 const 选择版本;

底层本质:const 修饰的是this指针,使其变为const 类类型* const,限制对对象的修改。

开发建议:只要成员函数不修改对象状态,就声明为 const 成员函数 ------ 这是 C++"常量正确性" 的最佳实践,能让代码更健壮、更易维护。

相关推荐
洋九八2 小时前
Hi3861 OpenHarmony 多线程操作、Timer 定时器、点灯、 IO 相关设备控制
开发语言·华为·harmonyos
星火开发设计2 小时前
using 关键字:命名空间的使用与注意事项
开发语言·c++·学习·算法·编程·知识
安全检测中2 小时前
序列化与反序列化学习
java·开发语言
进击的荆棘2 小时前
C++起始之路——string
开发语言·c++·stl
孞㐑¥2 小时前
算法—字符串
开发语言·c++·经验分享·笔记·算法
小龙报2 小时前
【数据结构与算法】单链表核心精讲:从概念到实战,吃透指针与动态内存操作
c语言·开发语言·数据结构·c++·人工智能·算法·链表
m5655bj2 小时前
通过 C# 设置 Word 文档背景颜色、背景图
开发语言·c#·word
野犬寒鸦2 小时前
从零起步学习并发编程 || 第二章:多线程与死锁在项目中的应用示例
java·开发语言·数据库·后端·学习
近津薪荼2 小时前
递归专题(1)——汉诺塔
c++·学习·算法