前置知识: C

C++ 类型系统

4 min中级

C++ 基本类型、类型推导、类型转换与类型安全。

前置知识

学习目标

  • 掌握「1. 常量 (Constants)」的核心机制、典型用法与常见陷阱
  • 掌握「2. 类型推导」的核心机制、典型用法与常见陷阱
  • 掌握「3. 类型别名」的核心机制、典型用法与常见陷阱
  • 掌握「4. 最佳实践」的核心机制、典型用法与常见陷阱
  • 掌握「5. 代码示例」的核心机制、典型用法与常见陷阱

1. 常量 (Constants)

1.1 const 常量

 // 全局常量
 const int MAX_VALUE = 100;
 int main() {
  // 局部常量
  const double PI = 3.14159;
  // 常量指针
  const int* p = &MAX_VALUE;
  // *p = 200; // 错误:不能修改 const 指针指向的值
  // 指针常量
  int x = 10;
  int* const q = &x;
  *q = 20; // 可以修改指针指向的值
  // q = &MAX_VALUE; // 错误:不能修改指针本身
  // const 引用
  const int& ref = x;
  // ref = 30; // 错误:不能修改 const 引用
  return 0;
 }

1.2 constexpr 常量 (C++11)

 // 编译期常量
 constexpr int factorial(int n) {
  return n <= 1 ? 1 : n * factorial(n - 1);
 }
 int main() {
  constexpr int fact5 = factorial(5); // 编译期计算
  std::cout << "5! = " << fact5 << std::endl;
  return 0;
 }

2. 类型推导

2.1 auto 类型推导 (C++11)

 #include <iostream>
 #include <vector>
 int main() {
  // 基本类型推导
  auto i = 10; // int
  auto d = 3.14; // double
  auto s = "Hello"; // const char*
  auto b = true; // bool
  // 容器类型推导
  std::vector<int> v = {1, 2, 3};
  auto it = v.begin(); // 迭代器类型
  // 函数返回类型推导
  auto add = [](int a, int b) { return a + b; }; // lambda 表达式
  std::cout << "add(5, 3) = " << add(5, 3) << std::endl;
  return 0;
 }

2.2 decltype 类型推导 (C++11)

 #include <iostream>
 int main() {
  int x = 10;
  decltype(x) y = 20; // y 的类型是 int
  double z = 3.14;
  decltype(x + z) w = x + z; // w 的类型是 double
  std::cout << "y = " << y << ", w = " << w << std::endl;
  return 0;
 }

3. 类型别名

3.1 typedef

 #include <iostream>
 // 类型别名
 typedef unsigned int uint;
 typedef std::vector<int> IntVector;
 int main() {
  uint x = 100;
  IntVector v = {1, 2, 3};
  std::cout << "x = " << x << std::endl;
  for (auto num : v) {
  std::cout << num << " ";
  }
  std::cout << std::endl;
  return 0;
 }

3.2 using 别名 (C++11)

 #include <iostream>
 #include <vector>
 // 使用 using 定义类型别名
 using uint = unsigned int;
 using IntVector = std::vector<int>;
 int main() {
  uint x = 100;
  IntVector v = {1, 2, 3};
  std::cout << "x = " << x << std::endl;
  for (auto num : v) {
  std::cout << num << " ";
  }
  std::cout << std::endl;
  return 0;
 }

4. 最佳实践

4.1 代码风格

4.1.1 命名规范

  • 变量和函数:camelCase 或 snake_case
  • 示例:int studentCount; 或 int student_count;
  • 示例:void calculateTotal(); 或 void calculate_total();
  • 类和结构体:PascalCase
  • 示例:class StudentRecord;
  • 示例:struct Point3D;
  • 常量:UPPER_CASE
  • 示例:const int MAX_SIZE = 100;
  • 示例:constexpr double PI = 3.14159;
  • 命名空间:lowercase
  • 示例:namespace utils;
  • 示例:namespace math_helpers;
  • 类型别名:PascalCase 或 camelCase
  • 示例:using IntVector = std::vector<int>;
  • 示例:typedef std::map<std::string, int> StringIntMap;

4.1.2 缩进和格式

  • 缩进:使用 4 个空格或 1 个制表符
  • 大括号:使用 K&R 风格(左大括号在同一行)
 if (condition) {
 // 代码
 }
  • 行长度:每行不超过 80-100 个字符
  • 空行:适当使用空行分隔代码块
  • 空格:在操作符前后、逗号后添加空格
 int result = a + b;
 func(a, b, c);

4.1.3 注释

  • 文档注释:函数前添加文档注释
 /**
 * @brief 计算两个数的和
 * @param a 第一个数
 * @param b 第二个数
 * @return 两数之和
 */
 int add(int a, int b) {
 return a + b;
 }
  • 代码注释:为复杂代码添加注释
 // 使用二分查找算法
 int binary_search(const std::vector<int>& arr, int target) {
 // 初始化左右边界
 int left = 0, right = arr.size() - 1;
 // 循环查找
 while (left <= right) {
 int mid = left + (right - left) / 2; // 避免整数溢出
 if (arr[mid] == target) {
 return mid;
 } else if (arr[mid] < target) {
 left = mid + 1;
 } else {
 right = mid - 1;
 }
 }
 return -1;
 }

4.2 类型使用建议

4.2.1 基本类型

  • 优先使用 auto:简化代码,提高可维护性
 auto result = calculate(); // 自动推导返回类型
 auto it = container.begin(); // 简化迭代器类型
  • 使用 constexpr:对于编译期常量,提高性能
 constexpr int MAX_SIZE = 100; // 编译期常量
 constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n-1); }
  • 合理使用 const:提高代码安全性和可读性
 const int& get_value() const; // 常量成员函数,不修改对象状态
 void process(const std::string& str); // 避免复制,且不修改参数
  • 注意类型转换:避免隐式类型转换导致的问题
 // 显式转换
 double d = 3.14;
 int i = static_cast<int>(d); // 明确转换意图

4.2.2 复合类型

  • 使用 STL 容器:优先使用标准库容器
 std::vector<int> numbers; // 动态数组
 std::map<std::string, int> scores; // 键值对
 std::unordered_set<int> unique_values; // 哈希集合
  • 智能指针:使用智能指针管理内存
 std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
 std::shared_ptr<MyClass> shared_ptr = std::make_shared<MyClass>();
  • 引用传递:对于大对象,使用引用传递避免复制
 void process_large_object(const LargeObject& obj); // 常量引用

4.3 控制流建议

  • 避免使用 goto:使用结构化控制流
  • 使用范围 for 循环:简化容器遍历
 for (const auto& item : container) {
 // 处理 item
 }
  • 合理使用 switch:对于多分支条件
  • 异常处理:使用 try-catch 处理异常

4.4 输入输出建议

  • 使用 std::cout 和 std::cin:标准库提供的输入输出功能
  • 格式化输出:使用 iomanip 库进行格式化
 std::cout << std::fixed << std::setprecision(2) << value << std::endl;
  • 错误处理:检查输入是否成功
 if (!(std::cin >> value)) {
 std::cerr << "Invalid input" << std::endl;
 std::cin.clear();
 std::cin.ignore();
 }
  • 避免使用 C 风格 I/O:如 printf 和 scanf

4.5 性能优化建议

  • 减少复制:使用移动语义和引用
  • 预分配内存:对于容器,提前分配足够的空间
 std::vector<int> vec;
 vec.reserve(1000); // 预分配空间
  • 避免频繁的内存分配:使用对象池或内存池
  • 内联函数:对于小函数,使用 inline 关键字
 inline int min(int a, int b) {
 return a < b ? a : b;
 }

5. 代码示例

5.1 温度转换

 #include <iostream>
 #include <iomanip>
 // 摄氏度转华氏度
 double celsius_to_fahrenheit(double celsius) {
  return (celsius * 9.0 / 5.0) + 32.0;
 }
 // 华氏度转摄氏度
 double fahrenheit_to_celsius(double fahrenheit) {
  return (fahrenheit - 32.0) * 5.0 / 9.0;
 }
 // 温度单位转换类
 class TemperatureConverter {
 public:
  static double celsius_to_fahrenheit(double celsius) {
  return (celsius * 9.0 / 5.0) + 32.0;
  }
  static double fahrenheit_to_celsius(double fahrenheit) {
  return (fahrenheit - 32.0) * 5.0 / 9.0;
  }
  static double celsius_to_kelvin(double celsius) {
  return celsius + 273.15;
  }
  static double kelvin_to_celsius(double kelvin) {
  return kelvin - 273.15;
  }
 }
 int main() {
  double c, f, k;
  std::cout << "输入摄氏度: ";
  std::cin >> c;
  f = TemperatureConverter::celsius_to_fahrenheit(c);
  k = TemperatureConverter::celsius_to_kelvin(c);
  std::cout << std::fixed << std::setprecision(2);
  std::cout << c << "°C = " << f << "°F = " << k << "K" << std::endl;
  std::cout << "输入华氏度: ";
  std::cin >> f;
  c = TemperatureConverter::fahrenheit_to_celsius(f);
  k = TemperatureConverter::celsius_to_kelvin(c);
  std::cout << f << "°F = " << c << "°C = " << k << "K" << std::endl;
  return 0;
 }

5.2 素数判断

 #include <iostream>
 #include <cmath>
 #include <vector>
 // 单个素数判断
 bool is_prime(int n) {
  if (n <= 1) return false;
  if (n == 2) return true;
  if (n % 2 == 0) return false;
  int sqrt_n = sqrt(n);
  for (int i = 3; i <= sqrt_n; i += 2) {
  if (n % i == 0) return false;
  }
  return true;
 }
 // 埃拉托斯特尼筛法生成素数列表
 std::vector<int> sieve_of_eratosthenes(int max) {
  std::vector<bool> is_prime(max + 1, true);
  std::vector<int> primes;
  is_prime[0] = is_prime[1] = false;
  for (int i = 2; i <= max; ++i) {
  if (is_prime[i]) {
  primes.push_back(i);
  for (int j = i * 2; j <= max; j += i) {
  is_prime[j] = false;
  }
  }
  }
  return primes;
 }
 // 素数工具类
 class PrimeUtils {
 public:
  static bool is_prime(int n) {
  if (n <= 1) return false;
  if (n == 2) return true;
  if (n % 2 == 0) return false;
  int sqrt_n = sqrt(n);
  for (int i = 3; i <= sqrt_n; i += 2) {
  if (n % i == 0) return false;
  }
  return true;
  }
  static std::vector<int> sieve_of_eratosthenes(int max) {
  std::vector<bool> is_prime(max + 1, true);
  std::vector<int> primes;
  is_prime[0] = is_prime[1] = false;
  for (int i = 2; i <= max; ++i) {
  if (is_prime[i]) {
  primes.push_back(i);
  for (int j = i * 2; j <= max; j += i) {
  is_prime[j] = false;
  }
  }
  }
  return primes;
  }
  static int count_primes(int max) {
  auto primes = sieve_of_eratosthenes(max);
  return primes.size();
  }
 }
 int main() {
  int n;
  std::cout << "输入一个整数: ";
  std::cin >> n;
  if (PrimeUtils::is_prime(n)) {
  std::cout << n << " 是素数" << std::endl;
  } else {
  std::cout << n << " 不是素数" << std::endl;
  }
  int max;
  std::cout << "输入最大值,生成素数列表: ";
  std::cin >> max;
  auto primes = PrimeUtils::sieve_of_eratosthenes(max);
  std::cout << "小于等于 " << max << " 的素数有 " << primes.size() << " 个: " << std::endl;
  for (int prime : primes) {
  std::cout << prime << " ";
  }
  std::cout << std::endl;
  return 0;
 }

5.3 数组操作

 #include <iostream>
 #include <vector>
 #include <algorithm>
 #include <numeric>
 // 计算数组和
 int sum_array(const std::vector<int>& arr) {
  int sum = 0;
  for (int num : arr) {
  sum += num;
  }
  return sum;
 }
 // 使用标准库计算数组和
 int sum_array_std(const std::vector<int>& arr) {
  return std::accumulate(arr.begin(), arr.end(), 0);
 }
 // 查找最大值
 int find_max(const std::vector<int>& arr) {
  if (arr.empty()) {
  throw std::runtime_error("Array is empty");
  }
  int max = arr[0];
  for (int num : arr) {
  if (num > max) {
  max = num;
  }
  }
  return max;
 }
 // 使用标准库查找最大值
 int find_max_std(const std::vector<int>& arr) {
  if (arr.empty()) {
  throw std::runtime_error("Array is empty");
  }
  return *std::max_element(arr.begin(), arr.end());
 }
 // 数组排序
 void sort_array(std::vector<int>& arr) {
  std::sort(arr.begin(), arr.end());
 }
 // 数组去重
 std::vector<int> remove_duplicates(const std::vector<int>& arr) {
  std::vector<int> result = arr;
  std::sort(result.begin(), result.end());
  auto last = std::unique(result.begin(), result.end());
  result.erase(last, result.end());
  return result;
 }
 // 数组工具类
 class ArrayUtils {
 public:
  static int sum(const std::vector<int>& arr) {
  return std::accumulate(arr.begin(), arr.end(), 0);
  }
  static int max(const std::vector<int>& arr) {
  if (arr.empty()) {
  throw std::runtime_error("Array is empty");
  }
  return *std::max_element(arr.begin(), arr.end());
  }
  static int min(const std::vector<int>& arr) {
  if (arr.empty()) {
  throw std::runtime_error("Array is empty");
  }
  return *std::min_element(arr.begin(), arr.end());
  }
  static double average(const std::vector<int>& arr) {
  if (arr.empty()) {
  throw std::runtime_error("Array is empty");
  }
  int sum = std::accumulate(arr.begin(), arr.end(), 0);
  return static_cast<double>(sum) / arr.size();
  }
  static void sort(std::vector<int>& arr, bool ascending = true) {
  if (ascending) {
  std::sort(arr.begin(), arr.end());
  } else {
  std::sort(arr.begin(), arr.end(), std::greater<int>());
  }
  }
  static std::vector<int> reverse(const std::vector<int>& arr) {
  std::vector<int> result = arr;
  std::reverse(result.begin(), result.end());
  return result;
  }
 }
 int main() {
  std::vector<int> numbers = {1, 5, 3, 9, 2, 5, 8, 3};
  std::cout << "原始数组: ";
  for (int num : numbers) {
  std::cout << num << " ";
  }
  std::cout << std::endl;
  std::cout << "数组和: " << ArrayUtils::sum(numbers) << std::endl;
  std::cout << "最大值: " << ArrayUtils::max(numbers) << std::endl;
  std::cout << "最小值: " << ArrayUtils::min(numbers) << std::endl;
  std::cout << "平均值: " << ArrayUtils::average(numbers) << std::endl;
  // 排序
  ArrayUtils::sort(numbers);
  std::cout << "排序后: ";
  for (int num : numbers) {
  std::cout << num << " ";
  }
  std::cout << std::endl;
  // 去重
  auto unique_numbers = remove_duplicates(numbers);
  std::cout << "去重后: ";
  for (int num : unique_numbers) {
  std::cout << num << " ";
  }
  std::cout << std::endl;
  // 反转
  auto reversed = ArrayUtils::reverse(numbers);
  std::cout << "反转后: ";
  for (int num : reversed) {
  std::cout << num << " ";
  }
  std::cout << std::endl;
  return 0;
 }

5.4 字符串操作

 #include <iostream>
 #include <string>
 #include <algorithm>
 #include <cctype>
 // 字符串工具类
 class StringUtils {
 public:
  // 字符串反转
  static std::string reverse(const std::string& str) {
  std::string result = str;
  std::reverse(result.begin(), result.end());
  return result;
  }
  // 字符串转大写
  static std::string to_upper(const std::string& str) {
  std::string result = str;
  std::transform(result.begin(), result.end(), result.begin(),
  [](unsigned char c) { return std::toupper(c); });
  return result;
  }
  // 字符串转小写
  static std::string to_lower(const std::string& str) {
  std::string result = str;
  std::transform(result.begin(), result.end(), result.begin(),
  [](unsigned char c) { return std::tolower(c); });
  return result;
  }
  // 去除首尾空格
  static std::string trim(const std::string& str) {
  size_t start = str.find_first_not_of(" \t\n\r");
  if (start == std::string::npos) return "";
  size_t end = str.find_last_not_of(" \t\n\r");
  return str.substr(start, end - start + 1);
  }
  // 检查是否是回文
  static bool is_palindrome(const std::string& str) {
  std::string cleaned;
  for (char c : str) {
  if (std::isalnum(c)) {
  cleaned += std::tolower(c);
  }
  }
  std::string reversed = cleaned;
  std::reverse(reversed.begin(), reversed.end());
  return cleaned == reversed;
  }
  // 统计单词数量
  static int count_words(const std::string& str) {
  int count = 0;
  bool in_word = false;
  for (char c : str) {
  if (std::isspace(c)) {
  in_word = false;
  } else if (!in_word) {
  in_word = true;
  count++;
  }
  }
  return count;
  }
 }
 int main() {
  std::string text = " Hello, World! ";
  std::cout << "原始字符串: '" << text << "'" << std::endl;
  std::cout << "去除空格: '" << StringUtils::trim(text) << "'" << std::endl;
  std::cout << "大写: '" << StringUtils::to_upper(text) << "'" << std::endl;
  std::cout << "小写: '" << StringUtils::to_lower(text) << "'" << std::endl;
  std::cout << "反转: '" << StringUtils::reverse(text) << "'" << std::endl;
  std::string palindrome = "A man a plan a canal Panama";
  std::cout << "是否回文: '" << palindrome << "' -> "
  << (StringUtils::is_palindrome(palindrome) ? "是" : "否") << std::endl;
  std::string sentence = "This is a test sentence";
  std::cout << "单词数量: '" << sentence << "' -> "
  << StringUtils::count_words(sentence) << std::endl;
  return 0;
 }

auto 与 decltype

基本写法:自动类型推导 auto <变量> = <表达式>;

// 编译器推导变量类型
auto x = 42;       // int
auto y = 3.14;     // double

基本写法:推导表达式类型 decltype(<表达式>) <变量> = <值>;

// 获取表达式的精确类型
int a = 0;
decltype(a) b = 1;

基本写法:decltype(auto) decltype(auto) <变量> = <表达式>;

// 保留引用与 cv 限定
decltype(auto) r = foo();

基本写法:尾置返回类型 auto <函数名>(<参数>) -> <返回类型> { }

// 后置返回类型用于模板
auto f(int x) -> double { return x; }

引用类型

基本写法:左值引用 <类型>& <变量> = <对象>;

// 绑定到左值
int a = 10;
int& ref = a;

基本写法:右值引用 <类型>&& <变量> = <右值>;

// 绑定到右值支持移动语义
int&& rref = 42;

基本写法:const 引用 const <类型>& <变量> = <值>;

// 可绑定到右值的常量引用
const int& cref = 100;

基本写法:转发引用 template <typename <T>> void <函数名>(<T>&& <参数>);

// 模板中的万能引用
template <typename T>
void wrapper(T&& arg);

类型转换

基本写法:static_cast static_cast<<目标类型>>(<表达式>)

// 编译期安全转换
double d = static_cast<double>(3);

基本写法:dynamic_cast dynamic_cast<<目标指针>>(<基类指针>)

// 运行时多态向下转换
Derived* p = dynamic_cast<Derived*>(base_ptr);

基本写法:const_cast const_cast<<目标类型>>(<表达式>)

// 移除或添加 const 限定
int& r = const_cast<int&>(cref);

基本写法:reinterpret_cast reinterpret_cast<<目标类型>>(<表达式>)

// 位模式重解释
long n = reinterpret_cast<long>(ptr);

cv 限定符

基本写法:const 变量 const <类型> <变量> = <值>;

// 不可修改的常量
const int max_size = 100;

基本写法:const 成员函数 <返回类型> <方法名>() const;

// 承诺不修改对象状态
int size() const { return n; }

基本写法:constexpr 变量 constexpr <类型> <变量> = <常量表达式>;

// 编译期常量
constexpr int size = 10;

基本写法:constexpr 函数 constexpr <返回类型> <函数名>(<参数>) { }

// 可在编译期求值的函数
constexpr int square(int x) { return x * x; }

类型别名

基本写法:using 别名 using <别名> = <类型>;

// 现代类型别名语法
using String = std::string;

基本写法:typedef 别名 typedef <类型> <别名>;

// 传统类型别名
typedef unsigned long ulong;

类型推断辅助

基本写法:auto 与引用结合 auto& <变量> = <对象>;

// 推导为左值引用避免拷贝
auto& ref = container;

基本写法:auto 与 const 结合 const auto& <变量> = <表达式>;

// 只读引用避免拷贝
const auto& item = vec[i];

强类型枚举

基本写法:枚举类 enum class <名称> { <枚举值> };

// 作用域安全枚举
enum class Color { Red, Green, Blue };

基本写法:指定底层类型 enum class <名称> : <整数类型> { };

// 指定底层类型为 uint8_t
enum class Flag : unsigned char { None = 0, All = 0xFF };

基本写法:访问枚举值 <枚举名>::<枚举值>

// 使用作用域访问
Color c = Color::Red;