C++学习:六个月从基础到就业——C++基础语法回顾:数据类型、变量与常量
本文是"C++学习:六个月从基础到就业"系列的第一篇技术文章,主要回顾C++的基本数据类型、变量定义和常量使用,为后续深入学习打下基础。查看完整系列目录了解更多内容。
引言
编程的本质是对数据的处理,而数据类型、变量与常量是任何编程语言的基础构建块。在C++中,对这些基础概念的深入理解不仅能让我们编写出正确的代码,还能帮助我们编写更高效、更安全的程序。本文将详细介绍C++中的数据类型、变量声明与常量定义,并探讨一些常见的陷阱和最佳实践。
基本数据类型
C++提供了丰富的内置数据类型,可以分为以下几类:
整型
整型用于表示整数值,根据大小和符号不同分为多种类型:
类型 | 关键字 | 典型大小 | 值范围 |
---|---|---|---|
字符型 | char | 1字节 | -128到127或0到255 |
整型 | int | 4字节 | − 2 31 -2^{31} −231到 2 31 − 1 2^{31-1} 231−1 |
短整型 | short | 2字节 | -32,768到32,767 |
长整型 | long | 至少4字节 | 至少 − 2 31 -2^{31} −231到 2 31 − 1 2^{31-1} 231−1 |
长长整型 | long long | 8字节 | − 2 63 -2^{63} −263到 2 63 − 1 2^{63-1} 263−1 |
每种整型都有对应的无符号版本,使用unsigned
关键字修饰:
unsigned int a = 42; // 只能存储非负数
unsigned char b = 255; // 范围是0-255
注意:整型的具体大小依赖于编译器和平台,表中给出的是最常见的大小。C++标准只规定了最小范围。
浮点型
浮点型用于表示实数:
类型 | 关键字 | 典型大小 | 精度 |
---|---|---|---|
单精度浮点 | float | 4字节 | 约7位十进制数字 |
双精度浮点 | double | 8字节 | 约15位十进制数字 |
扩展精度浮点 | long double | 至少8字节,通常16字节 | 取决于实现 |
浮点数的例子:
float pi_approx = 3.14f; // f后缀表示float类型
double precise_pi = 3.1415926535;
long double very_precise_pi = 3.1415926535897932384L; // L后缀表示long double
布尔型
布尔型用于表示真值或假值:
bool is_valid = true;
bool has_error = false;
字符型
字符型用于表示单个字符:
char ch = 'A'; // 单引号表示字符字面量
wchar_t wide_ch = L'你'; // 宽字符,用于表示Unicode字符
char16_t utf16_ch = u'你'; // UTF-16编码字符
char32_t utf32_ch = U'你'; // UTF-32编码字符
空类型
void类型表示没有值:
void function() {// 不返回任何值的函数
}
变量声明与初始化
变量是命名的内存位置,用于存储数据。在C++中,有多种方式可以声明和初始化变量。
变量声明
基本的变量声明语法为:
type variable_name; // 声明但不初始化
type variable_name = initial_value; // 声明并初始化
type variable_name(initial_value); // 构造函数风格的初始化
type variable_name{initial_value}; // 统一初始化(C++11)
例如:
int count; // 声明一个整型变量,未初始化(包含垃圾值)
int count = 0; // 声明并初始化为0
int count(0); // 等同于上一行
int count{0}; // C++11统一初始化语法
统一初始化(C++11)
C++11引入的花括号初始化(统一初始化)是推荐的初始化方式,它有以下优点:
- 防止窄化转换(narrowing conversion):
int a = 3.14; // 允许,但会截断为3
// int b{3.14}; // 错误:不允许窄化转换
int b{3}; // 正确
- 可以初始化数组和容器:
int array[] = {1, 2, 3, 4, 5};
std::vector<int> vec{1, 2, 3, 4, 5};
变量命名规则
变量名必须遵循以下规则:
- 只能包含字母、数字和下划线
- 必须以字母或下划线开头
- 区分大小写
- 不能使用C++关键字
常见的命名约定:
- 驼峰命名:
firstName
,lastName
- 下划线分隔:
first_name
,last_name
- 成员变量常使用前缀或后缀:
m_count
,count_
常量
常量是程序执行期间值不会改变的变量。C++提供了多种定义常量的方式。
const关键字
const关键字用于定义编译时常量或运行时常量:
const int MAX_STUDENTS = 30; // 编译时常量
const int array_size = get_size(); // 运行时常量,依赖于函数返回值
const也可以用于指针:
const int* p; // 指向常量的指针(不能通过p修改所指对象)
int* const p; // 常量指针(p不能指向其他对象)
const int* const p; // 指向常量的常量指针(两者都不能改变)
constexpr关键字(C++11)
constexpr用于定义编译时常量,并且编译器会在编译时计算其值:
constexpr int square(int x) {return x * x;
}constexpr int result = square(5); // 编译时计算为25
constexpr的优势在于它强制编译时求值,可以用在数组大小、模板参数等需要编译时常量的场合。
枚举常量
枚举是一种用户定义的类型,可以用来定义一组相关的常量:
// 传统枚举
enum Color {RED, // 默认值为0GREEN, // 1BLUE // 2
};// C++11引入的限定作用域枚举
enum class Fruit : int { // 可以指定底层类型APPLE,ORANGE,BANANA
};Color c = RED; // 正确
// int i = RED; // 正确,传统枚举可以隐式转换为整数
Fruit f = Fruit::APPLE; // 正确,必须使用作用域运算符
// int j = Fruit::APPLE; // 错误,限定作用域枚举不允许隐式转换
宏常量
虽然C++中仍然支持使用宏定义常量,但这是一种不推荐的方式:
#define PI 3.14159 // 不推荐
与const和constexpr相比,宏常量有以下缺点:
- 没有类型检查
- 容易导致意外的文本替换错误
- 难以调试
- 不遵守作用域规则
类型转换
C++中的类型转换分为隐式转换和显式转换。
隐式转换
当运算符作用于不同类型的操作数时,会进行隐式类型转换:
int i = 42;
double d = i; // 隐式将int转换为double
i = d; // 警告:隐式将double转换为int(可能丢失精度)
显式转换
C++提供了多种显式类型转换方式:
// C风格转换(不推荐)
int i = (int)3.14;// C++风格转换
int j = static_cast<int>(3.14); // 用于"合理"的转换
const int k = 42;
int* p = const_cast<int*>(&k); // 移除const限定(危险!)
C++风格的类型转换运算符包括:
static_cast
: 用于相关类型之间的转换const_cast
: 添加或移除const限定reinterpret_cast
: 在不相关类型之间进行转换(危险!)dynamic_cast
: 用于多态类的安全向下转型
类型推导(C++11)
C++11引入了auto和decltype关键字来实现类型推导。
auto关键字
auto关键字让编译器根据初始化表达式推导变量类型:
auto i = 42; // i是int类型
auto d = 3.14; // d是double类型
auto s = "hello"; // s是const char*类型
auto v = {1, 2, 3}; // v是std::initializer_list<int>类型
auto特别适用于复杂类型,如迭代器:
std::vector<int> vec = {1, 2, 3};
for (auto it = vec.begin(); it != vec.end(); ++it) {// 使用auto代替std::vector<int>::iterator
}
decltype关键字
decltype用于获取表达式的类型:
int i = 42;
decltype(i) j = i * 2; // j的类型与i相同,即intconst int& r = i;
decltype(r) s = j; // s的类型是const int&
实践与建议
-
总是初始化变量:未初始化的变量包含垃圾值,可能导致未定义行为。
-
优先使用统一初始化语法:
int i{42};
而不是int i = 42;
,以避免窄化转换。 -
使用sizeof运算符检查类型大小:
std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
-
谨慎使用隐式转换:尤其是可能导致精度丢失的转换。
-
优先使用const:如果变量不需要修改,将其声明为const。
-
使用constexpr进行编译时计算:可以提高性能并捕获错误。
-
避免使用宏:优先使用const、constexpr或枚举。
-
使用限定作用域枚举:
enum class
而不是传统的enum
。 -
了解变量的生命周期:自动变量、静态变量和动态分配的变量有不同的生命周期。
-
使用有意义的变量名:变量名应该清晰表达其用途。
代码示例:数据类型与变量综合运用
下面是一个综合例子,展示了C++中数据类型、变量和常量的用法:
#include <iostream>
#include <vector>
#include <string>// 使用constexpr进行编译时计算
constexpr int factorial(int n) {return n <= 1 ? 1 : n * factorial(n - 1);
}// 使用限定作用域枚举
enum class Season {SPRING,SUMMER,AUTUMN,WINTER
};int main() {// 整数类型int a{10};unsigned int b{20};long long c{1000000000LL}; // LL后缀表示long long字面量// 浮点类型float d{3.14f};double e{2.71828};// 字符和布尔类型char f{'A'};bool g{true};// 常量const double PI{3.14159265359};constexpr int FACTORIAL_5{factorial(5)}; // 编译时计算5!// 使用auto进行类型推导auto h = a + b; // h是unsigned intauto i = d * e; // i是double// 统一初始化的容器std::vector<int> vec{1, 2, 3, 4, 5};// 使用限定作用域枚举Season current_season{Season::SUMMER};// 输出结果std::cout << "a = " << a << ", size: " << sizeof(a) << " bytes" << std::endl;std::cout << "b = " << b << ", size: " << sizeof(b) << " bytes" << std::endl;std::cout << "c = " << c << ", size: " << sizeof(c) << " bytes" << std::endl;std::cout << "d = " << d << ", size: " << sizeof(d) << " bytes" << std::endl;std::cout << "e = " << e << ", size: " << sizeof(e) << " bytes" << std::endl;std::cout << "f = " << f << ", size: " << sizeof(f) << " bytes" << std::endl;std::cout << "g = " << std::boolalpha << g << ", size: " << sizeof(g) << " bytes" << std::endl;std::cout << "PI = " << PI << std::endl;std::cout << "5! = " << FACTORIAL_5 << std::endl;// 安全类型转换int j = static_cast<int>(e); // 从double转为intstd::cout << "e as int = " << j << std::endl;return 0;
}
总结
本文回顾了C++的基本数据类型、变量声明与初始化,以及常量定义。正确理解和使用这些基础概念,是编写高质量C++代码的第一步。在后续的文章中,我们将继续探索C++的其他基础特性,包括运算符、控制流结构和函数等。
希望这篇文章对你有所帮助。如果有任何问题或建议,欢迎在评论区留言讨论!
参考资料
- Bjarne Stroustrup. The C++ Programming Language (4th Edition)
- Scott Meyers. Effective Modern C++
- cppreference.com - 基本类型
- C++ Core Guidelines
这是我C++学习之旅系列的第一篇技术文章。查看完整系列目录了解更多内容。