C++变量与常量 #

一、变量概述 #

变量是程序中存储数据的容器,每个变量都有类型、名称和值。

1.1 变量定义 #

cpp
// 变量定义
int age;
double price;
char grade;
bool isValid;

1.2 变量初始化 #

C++支持多种初始化方式:

cpp
// 1. 传统初始化
int x = 10;

// 2. 构造函数初始化
int y(20);

// 3. 列表初始化(C++11)
int z{30};
int w = {40};

// 4. 默认初始化
int a;           // 未初始化,值不确定
static int b;    // 静态变量,默认初始化为0

1.3 列表初始化的优势 #

cpp
// 列表初始化会检查类型转换
int x = 3.14;      // 警告:浮点转整数,x = 3
int y{3.14};       // 错误:不允许窄化转换

// 建议使用列表初始化
int a{10};
double b{3.14};
char c{'A'};

二、变量命名规则 #

2.1 命名规则 #

  • 只能使用字母、数字、下划线
  • 必须以字母或下划线开头
  • 不能使用关键字
  • 区分大小写
  • 长度无限制(但不宜过长)
cpp
// 合法命名
int age;
int _count;
int userName;
int user_name;
int User123;

// 非法命名
int 2name;       // 不能以数字开头
int my-name;     // 不能包含连字符
int int;         // 不能使用关键字

2.2 命名规范 #

cpp
// 变量:小写字母+下划线 或 驼峰命名
int user_age;
int userAge;

// 常量:全大写+下划线
const int MAX_SIZE = 100;

// 类:大驼峰
class UserInfo {};

// 函数:小写+下划线 或 驼峰
void print_hello();
void printHello();

三、变量作用域 #

3.1 局部变量 #

在函数或代码块内定义的变量,作用域从定义处到代码块结束。

cpp
void func() {
    int x = 10;      // 局部变量
    {
        int y = 20;  // 块级变量
        // x 可见
        // y 可见
    }
    // x 可见
    // y 不可见
}

3.2 全局变量 #

在所有函数外定义的变量,作用域从定义处到文件结束。

cpp
#include <iostream>

int globalVar = 100;  // 全局变量

void func() {
    std::cout << globalVar << std::endl;
}

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

3.3 作用域示例 #

cpp
#include <iostream>

int x = 100;  // 全局变量

void test() {
    int x = 200;  // 局部变量,隐藏全局变量
    std::cout << "局部 x: " << x << std::endl;        // 200
    std::cout << "全局 x: " << ::x << std::endl;      // 100 (::是作用域解析运算符)
}

int main() {
    std::cout << "全局 x: " << x << std::endl;        // 100
    
    int x = 300;  // 局部变量
    std::cout << "局部 x: " << x << std::endl;        // 300
    std::cout << "全局 x: " << ::x << std::endl;      // 100
    
    test();
    
    return 0;
}

3.4 变量隐藏 #

cpp
int x = 10;  // 全局

int main() {
    int x = 20;     // 隐藏全局x
    {
        int x = 30; // 隐藏外层x
        std::cout << x << std::endl;    // 30
        std::cout << ::x << std::endl;  // 10
    }
    std::cout << x << std::endl;        // 20
    return 0;
}

四、常量 #

4.1 const常量 #

cpp
// const定义常量,必须初始化
const int MAX_SIZE = 100;
const double PI = 3.14159;
const char NEWLINE = '\n';

// const变量不能修改
MAX_SIZE = 200;  // 错误!

4.2 const与指针 #

cpp
int x = 10;
int y = 20;

// 1. 指向常量的指针(底层const)
const int* p1 = &x;
// *p1 = 20;  // 错误:不能通过p1修改值
p1 = &y;      // 正确:可以改变指向

// 2. 常量指针(顶层const)
int* const p2 = &x;
*p2 = 30;     // 正确:可以修改值
// p2 = &y;   // 错误:不能改变指向

// 3. 指向常量的常量指针
const int* const p3 = &x;
// *p3 = 40;  // 错误
// p3 = &y;   // 错误

记忆技巧:const在*左边修饰指向的值,const在*右边修饰指针本身。

4.3 constexpr(C++11) #

constexpr用于定义编译期常量:

cpp
// 编译期常量
constexpr int MAX_SIZE = 100;
constexpr double PI = 3.14159;

// constexpr函数
constexpr int square(int x) {
    return x * x;
}

constexpr int val = square(5);  // 编译期计算,val = 25

// const vs constexpr
const int a = 10;           // 运行期常量
constexpr int b = 10;       // 编译期常量

int n = 10;
const int c = n;            // 正确:运行期初始化
// constexpr int d = n;     // 错误:n不是编译期常量

4.4 const与constexpr的区别 #

特性 const constexpr
初始化时机 运行期或编译期 必须编译期
函数返回值 可以是运行期值 必须是编译期值
数组大小 部分支持 完全支持
模板参数 部分支持 完全支持
cpp
int n = 10;
const int a = n;           // 正确
// constexpr int b = n;    // 错误

constexpr int c = 10;      // 正确
int arr[c];                // 正确:编译期确定大小

const int d = 10;
int arr2[d];               // 正确(大多数编译器支持)

五、宏定义常量 #

5.1 #define定义常量 #

cpp
#define MAX_SIZE 100
#define PI 3.14159
#define NEWLINE '\n'

// 宏定义的问题
#define SQUARE(x) x * x
int result = SQUARE(1 + 2);  // 展开为 1 + 2 * 1 + 2 = 5,而不是9

// 正确的宏定义
#define SQUARE(x) ((x) * (x))
int result2 = SQUARE(1 + 2);  // ((1 + 2) * (1 + 2)) = 9

5.2 宏 vs const vs constexpr #

cpp
#define VALUE 100          // 宏:文本替换,无类型检查
const int value = 100;     // const:有类型检查,运行期
constexpr int Value = 100; // constexpr:有类型检查,编译期

// 推荐:优先使用const和constexpr
// 避免使用宏定义常量

六、auto类型推导 #

6.1 基本用法 #

cpp
// auto自动推导类型
auto x = 10;           // int
auto y = 3.14;         // double
auto z = "hello";      // const char*
auto b = true;         // bool
auto c = 'A';          // char

// 用于复杂类型
std::vector<int> vec = {1, 2, 3};
auto it = vec.begin(); // std::vector<int>::iterator

// 用于范围for循环
for (auto& item : vec) {
    std::cout << item << std::endl;
}

6.2 auto与引用 #

cpp
int x = 10;

auto a = x;      // int(拷贝)
auto& b = x;     // int&(引用)
const auto& c = x; // const int&(常量引用)

x = 20;
// a = 10(不变)
// b = 20(改变)
// c = 10(不变)

6.3 auto与const #

cpp
const int x = 10;

auto a = x;           // int(丢弃顶层const)
const auto b = x;     // const int
auto& c = x;          // const int&(保留const)

int y = 20;
const auto& d = y;    // const int&

七、decltype类型推导 #

7.1 基本用法 #

cpp
int x = 10;
decltype(x) y = 20;    // int y = 20

double d = 3.14;
decltype(d) e = 2.71;  // double e = 2.71

// 用于表达式
int a = 10, b = 20;
decltype(a + b) c;     // int c

7.2 decltype与auto的区别 #

cpp
int x = 10;

decltype(x) a = x;    // int
auto b = x;           // int

// 对于引用
int& ref = x;
decltype(ref) c = x;  // int&(保留引用)
auto d = ref;         // int(丢弃引用)

// 对于const
const int cx = 10;
decltype(cx) e = 10;  // const int(保留const)
auto f = cx;          // int(丢弃顶层const)

八、存储类 #

8.1 auto(旧含义) #

C++11之前,auto表示自动存储类,现已废弃。

8.2 static #

cpp
// 静态局部变量
void counter() {
    static int count = 0;  // 只初始化一次
    count++;
    std::cout << count << std::endl;
}

// 静态全局变量(文件作用域)
static int fileVar = 100;  // 只在本文件可见

// 静态成员变量
class MyClass {
    static int classVar;  // 类共享变量
};

8.3 extern #

cpp
// 声明外部变量
extern int globalVar;  // 声明,不定义

// 在另一个文件中定义
// int globalVar = 100;

8.4 register(已废弃) #

cpp
register int x = 10;  // 建议编译器放入寄存器(C++17废弃)

8.5 thread_local(C++11) #

cpp
thread_local int tlsVar = 0;  // 每个线程独立副本

九、总结 #

变量要点 #

概念 说明
定义 类型 + 变量名
初始化 =(){}
作用域 局部、全局、块级
auto 自动类型推导
decltype 获取表达式类型

常量要点 #

类型 说明
const 运行期常量
constexpr 编译期常量
#define 宏定义(不推荐)

最佳实践 #

cpp
// 1. 使用列表初始化
int x{10};

// 2. 使用const/constexpr代替宏
constexpr int MAX_SIZE = 100;

// 3. 使用auto简化复杂类型
auto it = vec.begin();

// 4. 避免全局变量

// 5. 变量就近定义
for (int i = 0; i < 10; i++) {
    // i在循环内有效
}

下一步,让我们学习基本数据类型!

最后更新:2026-03-26