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