0

0

C++如何在类中实现常量成员函数

P粉602998670

P粉602998670

发布时间:2025-09-22 11:14:01

|

380人浏览过

|

来源于php中文网

原创

常量成员函数通过在参数列表后加const关键字实现,承诺不修改对象非mutable成员,确保const对象可调用该函数。1. 它明确设计意图,使代码更安全、易读;2. 编译器强制检查,防止意外修改;3. 支持const正确性,允许const对象调用成员函数;4. mutable成员可在const函数中修改,用于缓存、日志等不影响逻辑状态的场景;5. const可参与函数重载,区分读写接口;6. 继承中const虚函数必须被const重写,保证多态安全;7. const指针/引用只能调用const函数,非const则无此限制。这一机制是C++类型安全和数据不可变保障的核心。

c++如何在类中实现常量成员函数

在C++的类中,要实现常量成员函数,核心机制就是在成员函数的参数列表后面加上

const
关键字。这不仅仅是一个语法标记,它向编译器承诺这个函数不会修改对象的状态,从而保证了代码的
const
正确性,并允许你对
const
对象或
const
引用调用这些方法。

解决方案

常量成员函数,顾名思义,是那些被设计为不修改其所属对象任何非

mutable
(可变)成员变量的函数。它的声明方式是在函数签名的末尾,紧跟在参数列表之后,加上
const
关键字。

class MyData {
private:
    int value;
    mutable int accessCount; // 用于统计访问次数,不影响对象逻辑状态
public:
    MyData(int v = 0) : value(v), accessCount(0) {}

    // 这是一个常量成员函数,因为它不会修改 'value'
    int getValue() const {
        // value = 10; // 错误:在const成员函数中不能修改非mutable成员
        accessCount++; // 可以修改mutable成员
        return value;
    }

    // 这是一个非常量成员函数,可以修改 'value'
    void setValue(int v) {
        value = v;
    }

    // 另一个常量成员函数,展示对mutable成员的修改
    int getAccessCount() const {
        return accessCount;
    }
};

// 示例使用
// MyData obj(42);
// const MyData constObj(100);

// obj.getValue(); // OK
// obj.setValue(50); // OK

// constObj.getValue(); // OK,因为getValue是const函数
// constObj.getAccessCount(); // OK
// constObj.setValue(200); // 错误:const对象不能调用非const函数

在我看来,这种机制是C++类型系统提供的一项强大保障。它强制我们思考函数对对象状态的影响,将“读取”操作与“修改”操作清晰地区分开来。当你在代码中看到一个

const
成员函数时,你立刻就知道调用它不会有任何副作用,这极大地提高了代码的可读性和安全性。

为什么我们需要常量成员函数?它带来了哪些实际好处?

坦白说,初学者可能觉得

const
有点麻烦,但一旦你深入理解,你会发现它带来的好处是实实在在的,甚至可以说,没有它,很多高级C++编程范式都难以实现。

立即学习C++免费学习笔记(深入)”;

首先,设计意图的明确性。一个函数被标记为

const
,就如同立下了一个契约:我保证不改变你(对象)的内部状态。这对于团队协作尤为重要。当其他开发者看到你的
const
函数时,他们知道可以放心地调用它,不必担心对象被意外修改。这是一种自我文档化的方式,比任何注释都更具强制力。

其次,编译器强制的安全保障。这不仅仅是语法糖,而是编译器在编译时进行的一项严格检查。如果你在

const
函数中尝试修改非
mutable
的成员变量,编译器会毫不留情地报错。这意味着许多潜在的逻辑错误和数据损坏问题,在代码运行之前就被扼杀在摇篮里。这种静态检查的价值,远超运行时调试。

再者,支持

const
正确性。这是C++中一个核心概念。当你有一个
const
对象、
const
引用或
const
指针时,你只能通过它们调用
const
成员函数。如果你的类中没有合适的
const
成员函数,那么这些
const
对象将变得几乎毫无用处,你无法安全地访问它们的任何数据。想象一下,你从一个
const
引用接收到一个对象,却无法读取它的任何属性,这显然是不可接受的。
const
成员函数解决了这个问题,它使得
const
对象也能参与到有意义的交互中。

最后,虽然不是最主要的,但

const
成员函数有时也能为编译器优化提供潜在的机会。当编译器知道一个函数不会修改对象状态时,它可能会做出一些更积极的优化,例如更好地利用寄存器,或者避免不必要的内存加载/存储操作。当然,现代编译器已经非常智能,这通常不是我们使用
const
的主要驱动力,但它确实是额外的好处。

const
成员函数内部能否修改成员变量?
mutable
关键字的作用是什么?

这是一个很常见的问题,也是理解

const
成员函数深度的关键。

基本原则是:

const
成员函数不能修改其所属对象的任何非
static
、非
mutable
的成员变量。这是
const
关键字的核心约束,也是其安全性的来源。

PHP与MySQL程序设计3
PHP与MySQL程序设计3

本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。 本书内容全面深入,适合各层次PHP和MySQL开发人员阅读,既是优秀的学习教程,也可用作参考手册。

下载

然而,规则总有例外。在

const
成员函数内部,你可以:

  1. 修改函数内部定义的局部变量。
  2. 调用同一类的其他
    const
    成员函数。
  3. 通过非
    const
    指针或引用修改其指向/引用的外部对象(但这通常被认为是糟糕的设计,因为它违背了
    const
    的承诺)。

不能

  1. 直接修改非
    mutable
    的成员变量。
  2. 直接调用同一类的非
    const
    成员函数(因为非
    const
    函数可能会修改对象状态)。

那么,

mutable
关键字是做什么的呢?
mutable
关键字是C++提供的一个“逃生舱门”,它允许你标记一个成员变量,使其即使在
const
成员函数中也可以被修改。

class Logger {
private:
    mutable std::string logBuffer; // 即使在const函数中也可以修改
    std::string name;
public:
    Logger(const std::string& n) : name(n) {}

    void log(const std::string& message) const {
        // 尽管是const函数,但可以修改mutable成员logBuffer
        logBuffer += message + "\n";
        // name = "New Name"; // 错误:不能修改非mutable成员
    }

    std::string getLog() const {
        return logBuffer;
    }
};

mutable
的使用场景通常是那些不影响对象“可观察状态”的内部实现细节:

  • 缓存机制: 当一个计算量大的结果需要被缓存起来,以供后续快速访问时,缓存本身的状态改变不应该影响对象的逻辑“值”。例如,一个
    const
    函数第一次被调用时计算并存储结果,后续直接返回缓存值。
  • 懒加载/延迟初始化: 某些成员变量只有在第一次被访问时才进行初始化,
    mutable
    可以用来标记这些变量。
  • 互斥锁: 在多线程环境中,即使是
    const
    函数,为了保护内部数据的访问,可能需要获取和释放一个
    std::mutex
    std::mutex
    通常被声明为
    mutable
    ,因为它本身的状态(锁是否被持有)与对象的逻辑状态无关。

我个人认为,

mutable
应该谨慎使用。它打破了
const
的承诺,如果滥用,会使代码变得难以理解和维护。只有当这种修改确实不改变对象的逻辑状态,仅仅是内部实现细节,且无法通过其他更“
const
友好”的方式实现时,才考虑使用它。

const
成员函数与重载、继承以及指针/引用有什么关系?

const
成员函数的设计,与C++的重载、继承以及指针/引用机制紧密结合,共同构成了
const
正确性的基石。

重载 (Overloading):

const
关键字可以作为函数签名的一部分,这意味着你可以为同一个函数名提供
const
和非
const
两个版本。

class Container {
private:
    int data[10];
public:
    // 非const版本,返回可修改的引用
    int& operator[](size_t index) {
        return data[index];
    }

    // const版本,返回const引用,不能修改
    const int& operator[](size_t index) const {
        return data[index];
    }
};

// Container c;
// c[0] = 10; // 调用非const operator[]
// const Container& cc = c;
// int val = cc[0]; // 调用const operator[]
// cc[0] = 20; // 错误:const引用不能修改

这种重载非常有用,它允许你根据对象的

const
属性,提供不同的行为。非
const
版本通常用于修改对象,而
const
版本则用于安全地读取对象。

继承 (Inheritance): 在继承体系中,基类的

const
成员函数可以在派生类中被重写(override)。关键在于,如果基类的函数是
const
的,那么派生类重写它的函数也必须是
const
。你不能将一个
const
函数重写为非
const
函数,反之亦然。这保证了多态调用时的
const
正确性。

class Base {
public:
    virtual void print() const {
        std::cout << "Base const print\n";
    }
    virtual void modify() {
        std::cout << "Base modify\n";
    }
};

class Derived : public Base {
public:
    void print() const override { // 必须是const
        std::cout << "Derived const print\n";
    }
    // void print() override { /* 错误:不能重写为非const */ }

    void modify() override { // 必须是非const
        std::cout << "Derived modify\n";
    }
};

// Base* b_ptr = new Derived();
// const Base* cb_ptr = new Derived();

// b_ptr->print(); // 调用Derived const print (即使b_ptr是非const,但print本身是const)
// cb_ptr->print(); // 调用Derived const print

// b_ptr->modify(); // 调用Derived modify
// cb_ptr->modify(); // 错误:const指针不能调用非const函数

这里有个小细节,如果

b_ptr
指向一个
Derived
对象,调用
b_ptr->print()
,虽然
b_ptr
是非
const
的,但由于
print()
函数本身就是
const
的,所以它会调用
Derived
const print
版本。

指针和引用 (Pointers and References): 这是

const
正确性最直接的应用场景。

  • 一个指向
    const
    对象的指针(
    const MyClass* ptr
    )或
    const
    引用(
    const MyClass& ref
    只能调用对象的
    const
    成员函数。
  • 一个指向非
    const
    对象的指针(
    MyClass* ptr
    )或非
    const
    引用(
    MyClass& ref
    可以调用对象的
    const
    和非
    const
    成员函数。
MyData obj(10);
MyData* ptr = &obj;
const MyData* const_ptr = &obj; // 指向const对象的指针
const MyData& const_ref = obj;   // const引用

ptr->setValue(20); // OK,ptr是非const,setValue是非const
ptr->getValue();   // OK,ptr是非const,getValue是const

// const_ptr->setValue(30); // 错误:const指针不能调用非const函数
const_ptr->getValue();   // OK,const指针可以调用const函数

// const_ref.setValue(40); // 错误:const引用不能调用非const函数
const_ref.getValue();   // OK,const引用可以调用const函数

这种机制确保了,一旦你通过一个

const
接口(
const
指针或
const
引用)访问对象,你就无法意外地修改它。这是C++中实现数据不可变性和安全性的核心手段,也是我个人在编写健壮代码时非常依赖的一个特性。它迫使你从设计层面就考虑清楚,哪些操作是只读的,哪些是可写的。

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

184

2023.09.27

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1465

2023.10.24

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

523

2023.09.20

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1018

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

63

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

407

2025.12.29

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 6.8万人学习

C 教程
C 教程

共75课时 | 4万人学习

C++教程
C++教程

共115课时 | 12.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号