设为首页 收藏本站
查看: 6|回复: 0

[经验分享] C++中类中const知识应用详解

[复制链接]
累计签到:53 天
连续签到:2 天
发表于 2025-5-22 11:32:46 | 显示全部楼层 |阅读模式
下面将从const 成员、const 成员函数、const 对象、mutable、constexpr 等方面,逐一详解 C++ 类中常见的 const 用法及注意事项,并配合示例。


一、const 数据成员
1.必须在初始化列表中初始化

[C++] 纯文本查看 复制代码
class A {
    const int x;    // const 成员
public:
    A(int v) : x(v) { }   // ❌ 合法:初始化列表中初始化
    // A(int v) { x = v; } // ❌ 错误:无法在函数体内赋值
};


2.不可修改

一旦初始化,之后在对象生存期内不能再改变。
可用于对外保证成员不被篡改。
与静态成员结合

[C++] 纯文本查看 复制代码
class B {
    static const int N = 100;  // 类内常量,若需要 ODR 定义,则在 cpp 中:
    // const int B::N; 
};


static const 整数/枚举成员可在类内直接给初始值,不占实例空间。

二、const 成员函数
在成员函数后添加 const,表明该函数不会修改任何非 mutable 成员,也不会调用非 const 成员函数。

[C++] 纯文本查看 复制代码
class C {
    int x;
public:
    C(int v): x(v) {}
    int  getX() const {      // 常量成员函数
        return x;             // 只能访问 x,不可修改
    }
    void setX(int v) {       // 非 const 函数
        x = v;
    }
};


调用约束

[C++] 纯文本查看 复制代码
const C c1(5);
c1.getX();     // ✅ 可以调用 const 成员函数
// c1.setX(7); // ❌ 错误:不能调用非 const 成员函数


隐式 this 类型
在 const 成员函数中,this 的类型为 const C*,保证不可修改成员。

三、const 对象
[C++] 纯文本查看 复制代码
C obj1(3);      // 普通对象
const C obj2(4); // 常量对象,只能调用 const 成员函数


只读语义:obj2 的所有非 static 数据成员对于外部都是只读的。

可与指针/引用混用:

[C++] 纯文本查看 复制代码
void foo(const C& c);
foo(obj1);    // OK,将 obj1 作为只读参数


四、mutable 修饰符
当你希望在 const 成员函数中仍然修改某些成员,可将它们声明为 mutable:

[C] 纯文本查看 复制代码
class Logger {
    mutable std::ostream& os;  // 即使在 const 函数中也可修改
public:
    Logger(std::ostream& _os): os(_os) {}
    void log(const std::string& msg) const {
        os << msg << std::endl; // OK,os 是 mutable
    }
};


场景:缓存、延迟初始化、统计访问次数等。

五、constexpr 与常量表达式
C++11 起,可将成员函数或构造函数声明为 constexpr,使其在编译期计算:

[C++] 纯文本查看 复制代码
class Point {
    int x, y;
public:
    constexpr Point(int _x, int _y): x(_x), y(_y) {}
    constexpr int getX() const { return x; }
    constexpr int getY() const { return y; }
};

constexpr Point p(1,2);
static_assert(p.getX() == 1, "");  // 在编译期验证


注意:

constexpr 成员函数 必须 同时 是 const(除了构造函数)。
只有在满足编译期求值规则时才真正成为常量表达式。

六、与继承结合
[C++] 纯文本查看 复制代码
struct Base {
    virtual void foo() const {
        // ...
    }
};
struct Derived : Base {
    void foo() const override { // 覆盖 const 成员函数
        // ...
    }
};


覆盖时签名要一致:返回类型、参数列表后是否 const 都要相同,否则不构成覆盖。

七、注意事项汇总
忘记在初始化列表中初始化 const 成员

会导致编译错误。
在 const 成员函数中尝试修改非 mutable 成员

编译器会报错,防止越界修改。
constexpr 函数应当尽量简单

包含循环与分支也支持,但要遵守常量表达式的限制。
不要滥用 mutable

可能破坏对象的逻辑常量性(logical constness),只在真正需要缓存、延迟初始化时使用。
接口设计

对于只读操作,应当标记为 const;有副作用的操作,要去除 const,让常量对象无法调用。


八、综合示例
[C++] 纯文本查看 复制代码
#include <iostream>
#include <vector>

class Matrix {
    const int rows, cols;           // 必须初始化
    std::vector<double> data;       // 默认构造
    mutable bool           dirty;   // 缓存标志
public:
    // constexpr 构造 + 初始化列表
    constexpr Matrix(int r, int c)
      : rows(r), cols(c), data(r*c), dirty(true) {}

    // const 成员函数:只读访问
    double get(int i, int j) const {
        dirty = false;             // OK:dirty 是 mutable
        return data[i*cols + j];
    }
    // 非 const 成员函数:修改
    void set(int i, int j, double v) {
        data[i*cols + j] = v;
        dirty = true;
    }

    constexpr int getRows() const { return rows; }
    constexpr int getCols() const { return cols; }

    bool isDirty() const { return dirty; }
};

int main() {
    Matrix M(2,3);
    M.set(0,0,1.23);
    std::cout << M.get(0,0) << "\n";    // 可以修改 dirty
    std::cout << std::boolalpha 
              << M.isDirty() << "\n";   // false
    constexpr Matrix N(3,3);
    static_assert(N.getRows()==3, "");  // 编译期校验
    return 0;
}




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-1005721-1-1.html 上篇帖子: Java/C++ 区别:看完这一篇,就够用! 下篇帖子: C++ 用实力碾碎所有否定,夺回本应属于它的地位
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表