Skip to content

C++ 常量

常量是其值在程序执行期间不能被修改的变量。在 C++ 中,可以使用多种方式定义常量。

1. 使用 const 关键字

const关键字是定义常量的最常用方式。

1.1 基本用法

cpp
#include <iostream>

int main() {
    const int MAX_SIZE = 100;
    const double PI = 3.14159;
    const char NEWLINE = '\n';
    
    std::cout << "MAX_SIZE: " << MAX_SIZE << std::endl;
    std::cout << "PI: " << PI << std::endl;
    
    // MAX_SIZE = 200;  // 错误:不能修改常量
    
    return 0;
}

1.2 const 指针

const与指针结合使用时,需要注意const的位置:

cpp
#include <iostream>

int main() {
    int a = 10;
    int b = 20;
    
    // 指向常量的指针
    const int* ptr1 = &a;
    // *ptr1 = 20;  // 错误:不能通过指针修改值
    ptr1 = &b;      // 可以修改指针指向
    
    // 常量指针
    int* const ptr2 = &a;
    *ptr2 = 20;     // 可以通过指针修改值
    // ptr2 = &b;   // 错误:不能修改指针指向
    
    // 指向常量的常量指针
    const int* const ptr3 = &a;
    // *ptr3 = 20;  // 错误:不能通过指针修改值
    // ptr3 = &b;   // 错误:不能修改指针指向
    
    return 0;
}

1.3 const 引用

const引用可以绑定到任何表达式,但不能通过引用修改值:

cpp
#include <iostream>

int main() {
    int a = 10;
    const int& ref = a;
    
    std::cout << "a = " << a << std::endl;
    // ref = 20;  // 错误:不能通过 const 引用修改值
    
    a = 20;  // 可以直接修改
    std::cout << "a = " << a << std::endl;
    
    return 0;
}

1.4 const 成员函数

在类中,const成员函数不能修改成员变量:

cpp
#include <iostream>
#include <string>

class Student {
private:
    std::string name;
    int age;

public:
    Student(std::string n, int a) : name(n), age(a) {}
    
    // const 成员函数
    void print() const {
        std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
        // age = 20;  // 错误:不能修改成员变量
    }
    
    // 非 const 成员函数
    void set_age(int a) {
        age = a;  // 可以修改成员变量
    }
};

int main() {
    const Student student("张三", 20);
    student.print();
    // student.set_age(21);  // 错误:不能调用非 const 成员函数
    
    return 0;
}

2. 使用 constexpr 关键字(C++11)

constexpr关键字用于定义常量表达式,在编译时计算值。

2.1 基本用法

cpp
#include <iostream>

constexpr int MAX_SIZE = 100;
constexpr double PI = 3.14159;

constexpr int square(int x) {
    return x * x;
}

int main() {
    constexpr int result = square(5);
    std::cout << "5 的平方: " << result << std::endl;
    
    int arr[MAX_SIZE];  // 使用 constexpr 常量定义数组大小
    
    return 0;
}

2.2 constexpr 与 const 的区别

  • const:运行时常量,值可以在运行时确定
  • constexpr:编译时常量,值必须在编译时确定
cpp
#include <iostream>

int main() {
    const int a = 10;        // 编译时常量
    int b = 20;
    const int c = b;         // 运行时常量
    
    constexpr int d = 10;    // 编译时常量
    // constexpr int e = b; // 错误:b 不是常量表达式
    
    return 0;
}

3. 使用 #define 预处理指令

#define预处理指令可以定义符号常量,但这种方式不推荐使用。

3.1 基本用法

cpp
#include <iostream>

#define MAX_SIZE 100
#define PI 3.14159

int main() {
    std::cout << "MAX_SIZE: " << MAX_SIZE << std::endl;
    std::cout << "PI: " << PI << std::endl;
    
    return 0;
}

3.2 #define 的缺点

  • 没有类型检查
  • 不遵循作用域规则
  • 可能导致意外的宏替换
cpp
#include <iostream>

#define SQUARE(x) x * x

int main() {
    int result = SQUARE(2 + 3);  // 展开为 2 + 3 * 2 + 3 = 11,而不是 25
    std::cout << "结果: " << result << std::endl;  // 输出: 11
    
    return 0;
}

4. 使用枚举

枚举类型可以定义一组命名的常量。

4.1 基本用法

cpp
#include <iostream>

enum Color {
    RED,
    GREEN,
    BLUE
};

int main() {
    Color color = RED;
    std::cout << "RED: " << RED << std::endl;
    std::cout << "GREEN: " << GREEN << std::endl;
    std::cout << "BLUE: " << BLUE << std::endl;
    
    return 0;
}

4.2 枚举类(C++11)

枚举类提供了更强的类型安全性:

cpp
#include <iostream>

enum class Color {
    RED,
    GREEN,
    BLUE
};

int main() {
    Color color = Color::RED;
    // std::cout << color << std::endl;  // 错误:不能直接输出枚举类
    std::cout << static_cast<int>(color) << std::endl;  // 输出: 0
    
    return 0;
}

5. 常量的命名规范

常量通常使用大写字母,单词之间用下划线分隔:

cpp
const int MAX_SIZE = 100;
const double PI = 3.14159;
const std::string DEFAULT_NAME = "Unknown";

6. 常量的作用域

常量的作用域与变量相同,可以是局部常量或全局常量。

6.1 局部常量

cpp
#include <iostream>

int main() {
    const int LOCAL_CONST = 10;
    std::cout << LOCAL_CONST << std::endl;
    return 0;
}

6.2 全局常量

cpp
#include <iostream>

const int GLOBAL_CONST = 100;

int main() {
    std::cout << GLOBAL_CONST << std::endl;
    return 0;
}

7. 常量表达式

常量表达式是在编译时可以计算其值的表达式。

7.1 常量表达式示例

cpp
#include <iostream>

constexpr int MAX_SIZE = 100;
constexpr int ARRAY_SIZE = MAX_SIZE * 2;

int main() {
    int arr[ARRAY_SIZE];  // 使用常量表达式定义数组大小
    std::cout << "数组大小: " << ARRAY_SIZE << std::endl;
    
    return 0;
}

8. const 与指针的详细说明

8.1 三种 const 指针形式

cpp
#include <iostream>

int main() {
    int a = 10;
    int b = 20;
    
    // 1. 指向常量的指针:不能通过指针修改值,但可以修改指针指向
    const int* ptr1 = &a;
    std::cout << "*ptr1 = " << *ptr1 << std::endl;
    // *ptr1 = 20;  // 错误
    ptr1 = &b;      // 正确
    
    // 2. 常量指针:不能修改指针指向,但可以通过指针修改值
    int* const ptr2 = &a;
    std::cout << "*ptr2 = " << *ptr2 << std::endl;
    *ptr2 = 20;     // 正确
    // ptr2 = &b;   // 错误
    
    // 3. 指向常量的常量指针:既不能修改指针指向,也不能通过指针修改值
    const int* const ptr3 = &a;
    std::cout << "*ptr3 = " << *ptr3 << std::endl;
    // *ptr3 = 20;  // 错误
    // ptr3 = &b;   // 错误
    
    return 0;
}

9. 示例:综合运用

现在,让我们看一个综合运用各种常量的例子:

cpp
#include <iostream>
#include <string>
#include <cmath>

// 全局常量
const int MAX_STUDENTS = 50;
constexpr double PI = 3.14159;

// 枚举
enum class Grade {
    A,
    B,
    C,
    D,
    F
};

// 类
class Circle {
private:
    double radius;

public:
    Circle(double r) : radius(r) {}
    
    // const 成员函数
    double area() const {
        return PI * radius * radius;
    }
    
    double circumference() const {
        return 2 * PI * radius;
    }
    
    void set_radius(double r) {
        radius = r;
    }
};

// constexpr 函数
constexpr int factorial(int n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

int main() {
    // const 变量
    const int age = 20;
    const double height = 1.75;
    const std::string name = "张三";
    
    // constexpr 变量
    constexpr int result = factorial(5);
    
    // 枚举
    Grade grade = Grade::A;
    
    // 类对象
    const Circle circle(5.0);
    std::cout << "圆的面积: " << circle.area() << std::endl;
    std::cout << "圆的周长: " << circle.circumference() << std::endl;
    
    // const 指针
    int a = 10;
    const int* ptr = &a;
    std::cout << "*ptr = " << *ptr << std::endl;
    
    // 输出常量
    std::cout << "\n常量值:" << std::endl;
    std::cout << "MAX_STUDENTS: " << MAX_STUDENTS << std::endl;
    std::cout << "PI: " << PI << std::endl;
    std::cout << "age: " << age << std::endl;
    std::cout << "height: " << height << std::endl;
    std::cout << "name: " << name << std::endl;
    std::cout << "grade: " << static_cast<int>(grade) << std::endl;
    std::cout << "5! = " << result << std::endl;
    
    return 0;
}

小结

C++ 常量包括:

  1. const 关键字

    • 定义常量变量
    • const 指针:指向常量的指针、常量指针、指向常量的常量指针
    • const 引用
    • const 成员函数
  2. constexpr 关键字(C++11):

    • 定义编译时常量
    • constexpr 函数
  3. #define 预处理指令

    • 定义符号常量(不推荐使用)
  4. 枚举

    • 定义一组命名的常量
    • 枚举类(C++11)
  5. 常量的命名规范

    • 使用大写字母
    • 单词之间用下划线分隔
  6. 常量的作用域

    • 局部常量
    • 全局常量
  7. 常量表达式

    • 在编译时可以计算其值的表达式

使用常量可以提高代码的可读性和可维护性,防止意外的修改。在后续章节中,我们将学习 C++ 的修饰符类型。