程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

人工智能:C++基础-const深度解析(c++中的const又玩出了新花样)

balukai 2025-03-17 15:58:29 文章精选 3 ℃

本质

在 C++ 里,const 的核心本质是一种约定,它向编译器和代码阅读者承诺

被 const 修饰的实体(变量、对象、函数等)在特定的作用域或规则下不会被修改

编译器会依据这个契约对代码进行检查,一旦发现违反契约的修改操作,就会在编译阶段报错,以此来增强代码的安全性和可维护性。

内核

从编译器角度来看,const 是编译时的概念。

编译器在编译过程中会严格检查对 const 修饰实体的操作,确保其只读性。

在内存层面,const 对象和普通对象一样占用内存空间,但编译器通过限制对其内存地址的写操作来实现只读特性。不过,如果通过一些非正规手段(如强制类型转换)绕过编译器检查,理论上是可以修改 const 对象的值的,但这违背了 const 的设计初衷。

使用场景

1. 常量

const int MAX_SIZE = 100;
// MAX_SIZE = 200;  // 编译错误,不能修改常量的值

用于定义程序中不会改变的常量,提高代码的可读性和可维护性,避免硬编码。

2. 变量

int value = 5;
const int constValue = value;
// constValue = 10;  // 编译错误,不能修改 const 变量

将变量声明为 const 可以防止意外修改,常用于需要保证值不变的场景。

3. 指针

  • 常量指针:指针指向的内容不能修改,但指针本身可以修改。
int num = 10;
const int* ptr1 = #
// *ptr1 = 20;  // 编译错误
int num2 = 20;
ptr1 = &num2;
  • 指针常量:指针本身不能修改,但指针指向的内容可以修改。
int num = 10;
int* const ptr2 = #
*ptr2 = 30;
// ptr2 = &num2;  // 编译错误
  • 指向常量的常量指针:指针本身和指向的内容都不能修改。
int num = 10;
const int* const ptr3 = #
// *ptr3 = 20;  // 编译错误
// ptr3 = &num2;  // 编译错误

4. 引用

int num = 10;
const int& ref = num;
// ref = 20;  // 编译错误,不能通过 const 引用修改引用的对象

使用 const 引用可以避免不必要的复制,同时保证引用的对象不被修改,常用于函数参数传递。

5. 函数的参数


void printValue(const int& value) {
    // value = 10;  // 编译错误,不能修改常量引用的值
    std::cout << value << std::endl;
}

int main() {
    int num = 5;
    printValue(num);
    return 0;
}

将函数参数声明为 const 可以防止函数内部修改传入的参数,增强代码的安全性,同时对于引用传递可以避免复制开销。

6. 函数的返回值

const int getValue() {
    return 10;
}

int main() {
    // getValue() = 20;  // 编译错误,不能修改常量返回值
    int result = getValue();
    return 0;
}

当函数返回一个常量值时,调用者不能修改这个返回值,常用于返回一些不应被修改的计算结果。

7. 类的成员变量

class MyClass {
private:
    const int id;
public:
    MyClass(int value) : id(value) {}
    // 成员变量 id 一旦初始化就不能再修改
};

将类的成员变量声明为 const,意味着该成员变量在对象创建时初始化后就不能再被修改,常用于表示对象的唯一标识等不变的属性。

8. 类的成员函数



收起

cpp

class MyClass {
private:
    int data;
public:
    MyClass(int value) : data(value) {}
    int getData() const {
        // data = 20;  // 编译错误,不能在常量成员函数中修改成员变量
        return data;
    }
};

int main() {
    const MyClass obj(10);
    int value = obj.getData();
    return 0;
}

使用 const 修饰类的成员函数表示该函数不会修改类的任何非 mutable 成员变量,这样的函数可以被 const 对象调用。

注意事项

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

class MyClass {
public:
    void nonConstFunction() {}
    void constFunction() const {}
};

int main() {
    const MyClass obj;
    // obj.nonConstFunction();  // 编译错误
    obj.constFunction();
    return 0;
}

const 对象的状态不能被改变,因此只能调用不会修改对象状态的 const 成员函数。

2.const与mutable结合使用

class MyClass {
private:
    mutable int counter;
public:
    MyClass() : counter(0) {}
    void incrementCounter() const {
        counter++;  // 可以在常量成员函数中修改 mutable 成员变量
    }
    int getCounter() const {
        return counter;
    }
};

int main() {
    const MyClass obj;
    obj.incrementCounter();
    std::cout << obj.getCounter() << std::endl;
    return 0;
}

mutable 关键字用于修饰类的成员变量,使得这些变量即使在 const 成员函数中也可以被修改,常用于实现一些与对象逻辑状态无关的计数或缓存功能。

3. 强制类型转换绕过const限制

虽然可以使用 const_cast 等强制类型转换来绕过 const 限制,但这是非常危险的操作,可能会导致未定义行为,应该尽量避免。

const int num = 10;
int* ptr = const_cast(&num);
*ptr = 20;  // 未定义行

4.const修饰函数重载

const 成员函数可以和非 const 成员函数构成重载,根据对象是否为 const 来选择调用不同的函数。

class MyClass {
private:
    int data;
public:
    MyClass(int value) : data(value) {}
    int& getData() { return data; }
    const int& getData() const { return data; }
};

int main() {
    MyClass obj(10);
    obj.getData() = 20;  // 调用非 const 版本

    const MyClass constObj(10);
    // constObj.getData() = 20;  // 编译错误,调用 const 版本
    return 0;
}
最近发表
标签列表