Skip to content

C++ 注释

概述

注释是代码中的文本说明,用于解释代码的目的、功能和实现细节。编译器会忽略注释内容,它们仅用于提高代码的可读性和可维护性。良好的注释习惯是专业编程的重要标志。

📝 注释类型

单行注释

cpp
#include <iostream>

int main() {
    // 这是单行注释
    int age = 25;  // 变量声明和初始化
    
    std::cout << "Hello World" << std::endl;  // 输出语句
    
    // 计算圆的面积
    double radius = 5.0;
    double area = 3.14159 * radius * radius;  // 面积公式:π * r²
    
    return 0;  // 函数返回值
}

多行注释

cpp
/*
 * 这是多行注释的示例
 * 可以跨越多行
 * 通常用于较长的说明
 */

#include <iostream>

/*
 * 函数名: calculateArea
 * 功能: 计算矩形面积
 * 参数: length - 长度, width - 宽度
 * 返回值: 矩形面积
 */
double calculateArea(double length, double width) {
    /*
     * 面积计算公式
     * Area = Length × Width
     */
    return length * width;
}

/* 主函数 */
int main() {
    double length = 10.0;  /* 矩形长度 */
    double width = 5.0;    /* 矩形宽度 */
    
    /* 调用函数计算面积 */
    double area = calculateArea(length, width);
    
    /* 输出结果 */
    std::cout << "矩形面积: " << area << std::endl;
    
    return 0;
}

嵌套注释问题

cpp
// 注意:C++的多行注释不能嵌套

/*
 * 这是外层注释
 /* 这个内层注释会导致问题 */
 * 因为第一个 */ 会结束整个注释块
 */

// 正确的做法是使用单行注释来"注释掉"包含多行注释的代码
// /*
// * 这样可以安全地注释掉多行注释
// * 不会产生嵌套问题
// */

// 或者使用预处理器指令
#if 0
/*
 * 这块代码不会被编译
 * 可以包含任何类型的注释
 */
int unused_function() {
    // 这些代码都不会被编译
    return 42;
}
#endif

🎨 注释风格和最佳实践

文件头注释

cpp
/**
 * @file: calculator.cpp
 * @author: 张三
 * @date: 2024-01-15
 * @version: 1.0
 * @description: 简单计算器程序,提供基本的数学运算功能
 * @copyright: Copyright (c) 2024
 */

#include <iostream>
#include <cmath>

/**
 * @brief 计算器类
 * 
 * 提供基本的数学运算功能,包括加减乘除和幂运算
 */
class Calculator {
public:
    /**
     * @brief 加法运算
     * @param a 第一个操作数
     * @param b 第二个操作数
     * @return 两数之和
     */
    static double add(double a, double b) {
        return a + b;
    }
    
    /**
     * @brief 除法运算
     * @param dividend 被除数
     * @param divisor 除数
     * @return 除法结果
     * @throws std::invalid_argument 当除数为0时抛出异常
     */
    static double divide(double dividend, double divisor) {
        if (divisor == 0) {
            throw std::invalid_argument("除数不能为零");
        }
        return dividend / divisor;
    }
};

函数注释

cpp
#include <vector>
#include <algorithm>

/**
 * @brief 在数组中查找目标值
 * 
 * 使用线性搜索算法在数组中查找指定的目标值。
 * 时间复杂度: O(n),空间复杂度: O(1)
 * 
 * @param arr 要搜索的数组
 * @param target 目标值
 * @return 如果找到目标值,返回其索引;否则返回-1
 * 
 * @example
 * std::vector<int> numbers = {1, 3, 5, 7, 9};
 * int index = linearSearch(numbers, 5);  // 返回2
 */
int linearSearch(const std::vector<int>& arr, int target) {
    // 遍历数组中的每个元素
    for (size_t i = 0; i < arr.size(); ++i) {
        // 如果找到目标值,返回索引
        if (arr[i] == target) {
            return static_cast<int>(i);
        }
    }
    
    // 未找到目标值
    return -1;
}

/**
 * @brief 快速排序算法实现
 * 
 * 递归实现的快速排序算法,平均时间复杂度为O(n log n)
 * 
 * @param arr 要排序的数组(会被修改)
 * @param low 排序范围的起始索引
 * @param high 排序范围的结束索引
 * 
 * @pre low >= 0 && high < arr.size()
 * @post arr[low..high] 按升序排列
 */
void quickSort(std::vector<int>& arr, int low, int high) {
    if (low < high) {
        // 分区操作,获取基准元素的正确位置
        int pivot = partition(arr, low, high);
        
        // 递归排序基准元素左侧的元素
        quickSort(arr, low, pivot - 1);
        
        // 递归排序基准元素右侧的元素
        quickSort(arr, pivot + 1, high);
    }
}

类和成员注释

cpp
/**
 * @brief 银行账户类
 * 
 * 模拟银行账户的基本操作,包括存款、取款和查询余额
 * 确保账户操作的安全性和数据完整性
 */
class BankAccount {
private:
    std::string accountNumber_;  ///< 账户号码
    std::string ownerName_;      ///< 账户持有人姓名
    double balance_;             ///< 账户余额
    bool isActive_;              ///< 账户是否激活
    
    /**
     * @brief 验证交易金额的有效性
     * @param amount 交易金额
     * @return 如果金额有效返回true,否则返回false
     */
    bool isValidAmount(double amount) const {
        return amount > 0 && amount <= 1000000;  // 单笔交易限额100万
    }
    
public:
    /**
     * @brief 构造函数
     * @param accountNumber 账户号码
     * @param ownerName 账户持有人姓名
     * @param initialBalance 初始余额(默认为0)
     */
    BankAccount(const std::string& accountNumber, 
                const std::string& ownerName, 
                double initialBalance = 0.0)
        : accountNumber_(accountNumber)
        , ownerName_(ownerName)
        , balance_(initialBalance)
        , isActive_(true) {
        // 验证初始余额
        if (initialBalance < 0) {
            throw std::invalid_argument("初始余额不能为负数");
        }
    }
    
    /**
     * @brief 存款操作
     * 
     * 向账户中存入指定金额,更新账户余额
     * 
     * @param amount 存款金额,必须大于0
     * @return 操作成功返回true,失败返回false
     * 
     * @warning 单笔存款金额不能超过100万
     */
    bool deposit(double amount) {
        // 检查账户状态
        if (!isActive_) {
            std::cerr << "账户已冻结,无法进行存款操作" << std::endl;
            return false;
        }
        
        // 验证存款金额
        if (!isValidAmount(amount)) {
            std::cerr << "无效的存款金额" << std::endl;
            return false;
        }
        
        // 执行存款操作
        balance_ += amount;
        std::cout << "存款成功,当前余额: " << balance_ << std::endl;
        return true;
    }
    
    /**
     * @brief 取款操作
     * 
     * @param amount 取款金额
     * @return 操作成功返回true,失败返回false
     * 
     * @note 取款金额不能超过当前余额
     */
    bool withdraw(double amount) {
        // 检查账户状态
        if (!isActive_) {
            std::cerr << "账户已冻结,无法进行取款操作" << std::endl;
            return false;
        }
        
        // 验证取款金额
        if (!isValidAmount(amount)) {
            std::cerr << "无效的取款金额" << std::endl;
            return false;
        }
        
        // 检查余额是否足够
        if (amount > balance_) {
            std::cerr << "余额不足,当前余额: " << balance_ << std::endl;
            return false;
        }
        
        // 执行取款操作
        balance_ -= amount;
        std::cout << "取款成功,当前余额: " << balance_ << std::endl;
        return true;
    }
    
    /**
     * @brief 获取账户余额
     * @return 当前账户余额
     */
    double getBalance() const {
        return balance_;
    }
};

📋 文档生成注释 (Doxygen)

Doxygen标签

cpp
/**
 * @brief 数学工具类
 * @details 提供常用的数学计算功能,包括基本运算、三角函数、对数函数等
 * @author 李四
 * @date 2024-01-15
 * @version 2.1.0
 * @since 1.0.0
 * @todo 添加更多高级数学函数
 * @bug 在极大数值时可能出现溢出
 * @warning 某些函数可能抛出异常
 */
class MathUtils {
public:
    /**
     * @brief 计算两个数的最大公约数
     * 
     * @param a 第一个整数
     * @param b 第二个整数
     * @return int 最大公约数
     * 
     * @par 算法
     * 使用欧几里得算法(辗转相除法)
     * 
     * @par 示例
     * @code
     * int gcd = MathUtils::gcd(48, 18);  // 返回6
     * @endcode
     * 
     * @see lcm()
     * @since 1.0.0
     */
    static int gcd(int a, int b) {
        // 使用递归实现欧几里得算法
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
    
    /**
     * @brief 计算两个数的最小公倍数
     * 
     * @param a 第一个整数
     * @param b 第二个整数
     * @return int 最小公倍数
     * 
     * @note 使用公式: lcm(a,b) = (a * b) / gcd(a,b)
     * 
     * @see gcd()
     * @since 1.0.0
     */
    static int lcm(int a, int b) {
        return (a * b) / gcd(a, b);
    }
    
    /**
     * @brief 判断一个数是否为质数
     * 
     * @param n 要检查的数
     * @return true 如果是质数
     * @return false 如果不是质数
     * 
     * @par 时间复杂度
     * O(√n)
     * 
     * @par 空间复杂度
     * O(1)
     * 
     * @pre n > 0
     * @post 返回值正确表示n是否为质数
     * 
     * @exception std::invalid_argument 当n <= 0时抛出
     */
    static bool isPrime(int n) {
        if (n <= 0) {
            throw std::invalid_argument("输入必须为正整数");
        }
        
        if (n <= 1) return false;      // 0和1不是质数
        if (n <= 3) return true;       // 2和3是质数
        if (n % 2 == 0 || n % 3 == 0) return false;  // 排除2和3的倍数
        
        // 检查5, 7, 11, 13, ...
        for (int i = 5; i * i <= n; i += 6) {
            if (n % i == 0 || n % (i + 2) == 0) {
                return false;
            }
        }
        
        return true;
    }
};

条件编译注释

cpp
#include <iostream>

// 调试宏定义
#ifdef DEBUG
    #define DBG_PRINT(x) std::cout << "DEBUG: " << x << std::endl
#else
    #define DBG_PRINT(x)  // 在非调试模式下为空
#endif

/**
 * @brief 演示条件编译的使用
 */
void demonstrateConditionalCompilation() {
    int value = 42;
    
    // 调试信息只在DEBUG模式下输出
    DBG_PRINT("变量value的值是: " << value);
    
    #ifdef ENABLE_LOGGING
        std::cout << "日志功能已启用" << std::endl;
    #endif
    
    #ifndef PRODUCTION_BUILD
        // 仅在非生产环境下的代码
        std::cout << "这是开发环境的调试代码" << std::endl;
    #endif
    
    // 平台特定代码
    #ifdef _WIN32
        std::cout << "运行在Windows平台" << std::endl;
    #elif defined(__linux__)
        std::cout << "运行在Linux平台" << std::endl;
    #elif defined(__APPLE__)
        std::cout << "运行在macOS平台" << std::endl;
    #else
        std::cout << "未知平台" << std::endl;
    #endif
}

🚫 注释的常见误区

不好的注释示例

cpp
// 不好的注释示例

// 增加i的值  ❌ 显而易见的注释
i++;

// 将x设置为0  ❌ 重复代码内容
int x = 0;

// 循环10次  ❌ 描述实现而非目的
for (int i = 0; i < 10; i++) {
    // TODO: 修复这个bug  ❌ 模糊的TODO
    process(i);
}

/* 这个函数很重要!!! */  ❌ 情绪化的注释
int importantFunction() {
    // 这里有一个hack  ❌ 承认代码质量问题但不解释
    return 42;
}

// 约翰写的代码,不要修改  ❌ 责任推卸
void johnsCode() {
    // 一些复杂的逻辑...
}

好的注释示例

cpp
// 好的注释示例

/**
 * @brief 使用二分查找算法在有序数组中查找元素
 * 
 * 由于数组已排序,我们可以使用二分查找来提高效率
 * 时间复杂度从O(n)降低到O(log n)
 */
int binarySearch(const std::vector<int>& arr, int target) {
    int left = 0;
    int 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;  // 未找到目标元素
}

/**
 * @brief 计算斐波那契数列的第n项
 * 
 * 使用动态规划方法避免重复计算,
 * 相比递归方法大大提高了效率
 */
long long fibonacci(int n) {
    if (n <= 1) return n;
    
    // 使用滚动数组优化空间复杂度
    long long prev2 = 0;  // f(n-2)
    long long prev1 = 1;  // f(n-1)
    long long current = 0;
    
    for (int i = 2; i <= n; i++) {
        current = prev1 + prev2;
        prev2 = prev1;
        prev1 = current;
    }
    
    return current;
}

// 业务逻辑:根据用户等级计算折扣
// VIP用户享受20%折扣,普通用户享受5%折扣
double calculateDiscount(UserLevel level, double amount) {
    const double VIP_DISCOUNT = 0.20;
    const double REGULAR_DISCOUNT = 0.05;
    
    switch (level) {
        case UserLevel::VIP:
            return amount * VIP_DISCOUNT;
        case UserLevel::Regular:
            return amount * REGULAR_DISCOUNT;
        default:
            return 0.0;  // 新用户无折扣
    }
}

🛠️ 注释工具和技巧

IDE注释快捷键

cpp
// 大多数IDE的注释快捷键:

// Visual Studio / VS Code:
// Ctrl + /           单行注释/取消注释
// Ctrl + Shift + /   多行注释/取消注释

// CLion / IntelliJ:
// Ctrl + /           单行注释/取消注释
// Ctrl + Shift + /   多行注释/取消注释

// 注释模板示例
/**
 * @brief ${函数功能描述}
 * 
 * @param ${参数名} ${参数描述}
 * @return ${返回值描述}
 * 
 * @author ${作者}
 * @date ${日期}
 */

注释维护建议

cpp
#include <iostream>
#include <vector>

/**
 * @brief 数据处理类
 * @version 2.0.0
 * @changelog
 * - v2.0.0: 重构了数据处理算法,提高了性能
 * - v1.5.0: 添加了错误处理机制
 * - v1.0.0: 初始版本
 */
class DataProcessor {
private:
    std::vector<int> data_;
    
public:
    /**
     * @brief 处理数据
     * 
     * @deprecated 此方法已弃用,请使用processDataV2()
     * @see processDataV2()
     */
    [[deprecated("使用processDataV2()替代")]]
    void processData() {
        // 旧的处理逻辑...
    }
    
    /**
     * @brief 新版本的数据处理方法
     * 
     * 相比旧版本提高了50%的性能,并增加了错误处理
     * 
     * @since 2.0.0
     */
    void processDataV2() {
        // 新的优化处理逻辑...
        try {
            // 处理数据...
        } catch (const std::exception& e) {
            std::cerr << "数据处理错误: " << e.what() << std::endl;
        }
    }
};

总结

注释是代码文档化的重要手段,良好的注释习惯包括:

注释原则

  • 解释为什么,而不是是什么:注释应该说明代码的目的和原因
  • 保持注释与代码同步:修改代码时及时更新注释
  • 避免显而易见的注释:不要注释一目了然的代码
  • 使用一致的风格:团队应该统一注释格式和风格

注释类型用途

  • 单行注释 (//) :简短说明、临时标记
  • 多行注释 (/ /) :详细文档、大段说明
  • 文档注释 :API文档、自动生成文档

最佳实践

  • 在复杂算法前添加说明
  • 为公共接口编写详细文档
  • 使用标准化的文档格式(如Doxygen)
  • 避免注释掉的代码长期存在

良好的注释不仅帮助其他开发者理解代码,也有助于你在未来维护自己的代码。

本站内容仅供学习和研究使用。