找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4064

积分

0

好友

545

主题
发表于 3 小时前 | 查看: 2| 回复: 0

在C++面试中,const int* pint const* pint* const p 的区别几乎是必考题。掌握它不仅是应付面试,更是理解C++类型安全和设计哲学的关键。

一个让你终身不忘的口诀

“左定值,右定向”。

这六个字是什么意思?我们直接通过例子来理解,避免晦涩的理论。

int a = 10;
int b = 20;

const int* p1 = &a;  // const在*左边
int const* p2 = &a;  // const在*左边,和上面等价
int* const p3 = &a;  // const在*右边

第一种和第二种写法完全等价!const* 左边,表示 “指向的值不能通过这个指针修改”,但指针本身可以指向别的地址。

*p1 = 15;  // 编译错误!不能通过p1修改a的值
p1 = &b;   // 合法!p1可以指向b

第三种,const* 右边,表示 “指针本身存储的地址不能改”,但指向的值可以通过这个指针修改。

*p3 = 15;  // 合法!可以通过p3修改a的值
p3 = &b;   // 编译错误!p3不能重新指向其他地址

核心规则就这么简单,牢牢记住“左定值,右定向”即可。

C++ const指针位置对比示意图

为何会有这种设计?

我们需要理解编译器的视角。const 关键字本质上是进行 “访问权限控制”

const* 左边时,编译器理解为你做出了一个承诺:“这个指针不会修改它指向的内容”。这在函数参数传递中极其有用,是一种良好的编程契约。例如:

void printArray(const int* arr, int size){
    for(int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
}

这里使用 const int* arr 明确告知函数的调用者:“请放心把数组传给我,我承诺不会修改你的数据”。这体现了C++的“契约精神”,能有效防止意外修改,提升代码安全性。

const* 右边时,编译器理解为:“这个指针变量本身的地址是固定的”。这种用法在类成员变量中较为常见。

class MyClass {
    int* const p;  // 这个指针一旦初始化就不能更改指向
public:
    MyClass(int* ptr) : p(ptr) {}  // 必须在初始化列表里初始化
};

扩展到const成员函数

面试官通常不会只问指针,紧接着就会问:“那 const 成员函数呢?”

首先需要理解 this 指针的变化。

  • 在普通成员函数内部,this 指针的类型是 MyClass* const。这意味着指针本身不能改(由编译器保证),但指向的对象(即对象的成员变量)可以被修改。
  • const 成员函数内部,this 指针的类型变成了 const MyClass* const。这意味着不仅指针本身不能改,通过 this 指针访问到的对象内容(成员变量)也被视为不可修改
class Person {
    string name;
    int age;
public:
    // const成员函数,承诺不修改任何成员变量
    void showInfo() const {
        cout << name << " " << age << endl;
        // age = 30;  // 编译错误!不能在const成员函数内修改成员变量
    }

    void setAge(int a){
        age = a;  // 普通成员函数,可以修改成员变量
    }
};

const对象只能调用const成员函数

这是一个核心规则,必须牢记:

const Person p1("张三", 25);
p1.showInfo();  // 合法!const对象调用const成员函数
p1.setAge(30);  // 编译错误!const对象不能调用非const成员函数

Person p2("李四", 30);
p2.showInfo();  // 合法!普通对象可以调用const成员函数
p2.setAge(35);  // 合法!普通对象可以调用非const成员函数

为什么这样设计?逻辑很清晰:如果允许 const 对象调用非 const 成员函数,那么该函数就有可能修改对象状态,这直接违背了 const 对象“不可修改”的语义。编译器必须在编译期就杜绝这种可能性。

C++ const与非const对象调用成员函数的权限规则

实战场景:设计一个不可修改的配置类

让我们来看一个实战例子。假设你需要设计一个配置管理系统,要求配置对象一旦创建就不可修改,但可以被多个模块安全地读取。

class AppConfig {
private:
    const string dbHost;          // const成员变量,必须在初始化列表初始化
    const int maxConnections;
    const int timeout;
    vector<string> allowedUsers;   // 普通成员变量,但在const对象中也不能被const成员函数修改

public:
    AppConfig(const string& host, int maxConn, int time)
        : dbHost(host), maxConnections(maxConn), timeout(time) {
        allowedUsers.push_back("admin");
    }

    // 所有getter都是const成员函数,提供只读访问接口
    const string& getDbHost() const{
        return dbHost;
    }

    int getMaxConnections() const{
        return maxConnections;
    }

    const vector<string>& getAllowedUsers() const{
        return allowedUsers;
    }

    // 注意:没有提供任何setter方法,从接口层面确保对象不可修改
};

使用示例:

void initializeService(const AppConfig& config){
    string host = config.getDbHost();              // 合法
    int maxConn = config.getMaxConnections();      // 合法

    // config.dbHost = "newhost";  // 编译错误!dbHost是const成员
    // config.setDbHost("newhost"); // 编译错误!类设计时就没提供setter
}

int main(){
    AppConfig config("localhost", 100, 30);
    initializeService(config);
    return 0;
}

在这个设计中,const 发挥了双重作用:

  1. const成员变量 确保了核心配置项在构造后不可更改。
  2. const成员函数 & const引用传递 构成了编译期的安全保证。当以 const AppConfig& 形式传递对象时,编译器会确保没有任何代码能调用可能修改该对象的函数。

这就是“const正确性”(const-correctness)的设计哲学,它能使你的代码更健壮、意图更清晰,是编写高质量、可维护C++代码的重要实践,也是面试求职中考察候选人代码素养的常见点。

mutable关键字的用途

有时,我们可能需要在 const 成员函数中修改某些特定的成员变量,例如为了实现缓存机制。这时就需要使用 mutable 关键字。

class DataProcessor {
    vector<int> data;
    mutable int cachedSum;    // mutable成员,即使在const函数里也能修改
    mutable bool cacheValid;

public:
    int getSum() const{
        if(!cacheValid) {
            cachedSum = 0;
            for(int num : data) {
                cachedSum += num;
            }
            cacheValid = true;  // 在const成员函数中修改mutable变量是允许的
        }
        return cachedSum;
    }

    void addData(int num){
        data.push_back(num);
        cacheValid = false;  // 数据变化,缓存失效
    }
};

mutable 是一个例外,它告诉编译器:“这个变量虽然位于 const 对象或 const 成员函数中,但我需要修改它,请放行”。使用 mutable 需要谨慎,它不应被滥用来破坏 const 语义,而只应用于这种不影响对象“逻辑状态”(logical constness)的场合,比如缓存、调试计数、线程同步原语等。

希望这篇从口诀到原理,再到实战的解析,能帮助你彻底掌握C++中 const 与指针、成员函数的各种用法。理解并善用 const,是迈向成熟C++开发者的关键一步。如果你想深入探讨更多C++核心话题,欢迎到技术社区云栈社区交流分享。




上一篇:C语言指针:深度解析虚拟地址与物理地址的底层原理与程序运行环境
下一篇:Mistral Leanstral:首个开源Lean 4代码代理,破解AI编程的形式化验证瓶颈
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-18 09:07 , Processed in 0.624834 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

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