Skip to content

C++ 代码规范

概述

代码规范是团队协作和代码维护的重要基础。良好的代码规范提高代码可读性、减少错误、促进团队协作。本章介绍C++代码规范的各个方面,包括命名规范、格式规范、注释规范等。

📝 命名规范

变量和函数命名

cpp
// ✅ 良好的命名
class UserAccount {
private:
    std::string username_;           // 成员变量用下划线后缀
    std::string email_address_;      // 描述性命名
    int account_id_;                 // 小写+下划线
    
public:
    // 函数名:动词开头,驼峰式
    void setUsername(const std::string& username);
    std::string getUsername() const;
    
    // 布尔函数用is/has/can开头
    bool isActive() const;
    bool hasValidEmail() const;
    bool canLogin() const;
    
    // 私有辅助函数
    void validateInput_(const std::string& input);
};

// 局部变量
void processUserData() {
    int user_count = 0;              // 小写+下划线
    std::string temp_filename;       // 描述性命名
    bool is_valid = false;           // 布尔变量清晰表意
    
    // 循环变量可以简短
    for (int i = 0; i < user_count; ++i) {
        // 处理逻辑
    }
    
    // 范围for循环使用描述性名称
    for (const auto& user : user_list) {
        // 处理每个用户
    }
}

// ❌ 不良的命名
class ua {                          // 类名太短
    std::string n;                  // 变量名无意义
    int data;                       // 过于通用
    
public:
    void DoSomething();             // 函数名不清楚
    bool Check();                   // 检查什么?
    int get();                      // 获取什么?
};

类和结构体命名

cpp
// ✅ 类命名规范
class DatabaseConnection {          // 大驼峰命名
    // 实现
};

class HttpRequestHandler {          // 清晰的职责描述
    // 实现
};

struct ConfigurationSettings {      // 结构体同样使用大驼峰
    std::string server_address;
    int port_number;
    bool enable_ssl;
};

// 模板类
template<typename T>
class SmartPointer {               // 模板参数T简洁明了
    // 实现
};

template<typename Container, typename Predicate>
class FilteredView {               // 模板参数描述性命名
    // 实现
};

// 枚举类
enum class ConnectionStatus {      // 枚举类使用大驼峰
    kDisconnected,                 // 枚举值用k前缀
    kConnecting,
    kConnected,
    kError
};

enum class LogLevel {
    kDebug = 0,
    kInfo = 1,
    kWarning = 2,
    kError = 3,
    kCritical = 4
};

常量和宏定义

cpp
// ✅ 常量命名
namespace config {
    // 编译时常量
    constexpr int kMaxConnections = 100;
    constexpr double kPi = 3.14159265359;
    constexpr char kDefaultEncoding[] = "UTF-8";
    
    // 全局常量
    const std::string kApplicationName = "MyApp";
    const std::chrono::seconds kTimeout{30};
}

// 类内常量
class Buffer {
private:
    static constexpr size_t kDefaultSize = 1024;
    static constexpr size_t kMaxSize = 65536;
    
public:
    static const std::string kVersion;
};

// 宏定义(应该尽量避免)
#define MY_APP_VERSION_MAJOR 1
#define MY_APP_VERSION_MINOR 0
#define MY_APP_DEBUG_ENABLED 1

// 函数式宏
#define ASSERT_MSG(condition, message) \
    do { \
        if (!(condition)) { \
            std::cerr << "Assertion failed: " << message << std::endl; \
            abort(); \
        } \
    } while(0)

🔧 格式规范

缩进和空格

cpp
// ✅ 正确的缩进(使用4个空格或1个Tab)
class Example {
public:
    void method() {
        if (condition) {
            for (int i = 0; i < count; ++i) {
                process(i);
            }
        }
    }
    
private:
    int member_variable_;
};

// 函数参数对齐
void longFunctionName(
    const std::string& first_parameter,
    const std::string& second_parameter,
    int third_parameter,
    bool fourth_parameter) {
    // 实现
}

// 或者
void longFunctionName(const std::string& first_parameter,
                     const std::string& second_parameter,
                     int third_parameter,
                     bool fourth_parameter) {
    // 实现
}

括号和换行

cpp
// ✅ 推荐的括号风格
namespace my_namespace {

class MyClass {
public:
    MyClass() {
        // 构造函数实现
    }
    
    void method() {
        if (condition) {
            // if语句体
        } else {
            // else语句体
        }
        
        for (int i = 0; i < count; ++i) {
            // 循环体
        }
        
        try {
            // 尝试执行的代码
        } catch (const std::exception& e) {
            // 异常处理
        }
    }
    
private:
    int value_;
};

}  // namespace my_namespace

// 单行可以省略括号(但要谨慎)
if (simple_condition) 
    simple_action();

// 复杂表达式要换行
if (very_long_condition_that_spans_multiple_lines &&
    another_condition_that_is_also_long &&
    yet_another_condition) {
    // 处理逻辑
}

空行和空格使用

cpp
// ✅ 合理的空行使用
#include <iostream>
#include <string>
#include <vector>

namespace utilities {

const int kMaxRetries = 3;

class NetworkManager {
public:
    // 构造函数
    NetworkManager();
    ~NetworkManager();
    
    // 主要接口
    bool connect(const std::string& host, int port);
    void disconnect();
    
    // 数据传输
    bool sendData(const std::vector<uint8_t>& data);
    std::vector<uint8_t> receiveData();
    
private:
    // 私有辅助方法
    bool establishConnection_();
    void cleanup_();
    
    // 成员变量
    std::string host_;
    int port_;
    bool is_connected_;
};

}  // namespace utilities

// 运算符周围的空格
int result = a + b * c;
bool is_valid = (x > 0) && (y < max_value);
array[index] = new_value;
function_call(param1, param2, param3);

// 指针和引用的空格
int* pointer;                    // 或 int *pointer;
int& reference = value;          // 或 int &reference = value;
const std::string& name = getName();

📖 注释规范

文档注释

cpp
/**
 * @brief 用户账户管理类
 * 
 * 这个类负责管理用户账户的创建、验证和维护。
 * 支持多种认证方式和权限管理。
 * 
 * @author John Doe
 * @version 1.2.0
 * @since 1.0.0
 * 
 * @example
 * ```cpp
 * UserManager manager;
 * if (manager.createUser("alice", "password123")) {
 *     std::cout << "用户创建成功" << std::endl;
 * }
 * ```
 */
class UserManager {
public:
    /**
     * @brief 创建新用户账户
     * 
     * @param username 用户名,长度应在3-20字符之间
     * @param password 密码,至少8个字符,包含字母和数字
     * @return true 创建成功
     * @return false 创建失败(用户名已存在或参数无效)
     * 
     * @throws std::invalid_argument 当用户名或密码格式无效时
     * @throws std::runtime_error 当数据库操作失败时
     * 
     * @note 密码会自动进行哈希处理
     * @warning 此方法不是线程安全的
     * 
     * @see validateUsername()
     * @see validatePassword()
     */
    bool createUser(const std::string& username, const std::string& password);
    
    /**
     * @brief 验证用户凭据
     * 
     * @param username 用户名
     * @param password 明文密码
     * @return 验证成功返回用户ID,失败返回-1
     */
    int authenticateUser(const std::string& username, 
                        const std::string& password);
    
private:
    /**
     * @brief 验证用户名格式
     * @param username 待验证的用户名
     * @return 格式正确返回true
     */
    bool validateUsername_(const std::string& username);
};

行内注释

cpp
void processData() {
    // 初始化缓冲区
    std::vector<uint8_t> buffer(kBufferSize);
    
    // FIXME: 这里可能存在内存泄漏
    int* temp_data = new int[size];
    
    // TODO: 优化这个算法的性能
    for (int i = 0; i < data_count; ++i) {
        // 跳过无效数据
        if (data[i] < 0) continue;
        
        // 应用复杂的变换公式
        // y = ax² + bx + c
        double result = a * data[i] * data[i] + b * data[i] + c;
        
        processed_data.push_back(result);
    }
    
    // HACK: 临时解决方案,需要重构
    if (legacy_mode) {
        convertToLegacyFormat();
    }
    
    delete[] temp_data;  // 释放临时内存
}

// 复杂算法的注释
void quickSort(std::vector<int>& arr, int low, int high) {
    if (low < high) {
        // 分区操作:将数组分为小于和大于pivot的两部分
        int pivot_index = partition(arr, low, high);
        
        // 递归排序左半部分(小于pivot)
        quickSort(arr, low, pivot_index - 1);
        
        // 递归排序右半部分(大于pivot)
        quickSort(arr, pivot_index + 1, high);
    }
}

特殊注释标记

cpp
class ApiClient {
public:
    // NOTE: 这个方法会阻塞线程直到请求完成
    std::string makeRequest(const std::string& url);
    
    // WARNING: 这个方法已废弃,请使用makeAsyncRequest
    [[deprecated("Use makeAsyncRequest instead")]]
    std::string makeSyncRequest(const std::string& url);
    
    // XXX: 临时实现,需要重写
    void temporaryWorkaround();
    
private:
    // PERF: 这个函数可能成为性能瓶颈
    void heavyComputation();
    
    // SECURITY: 确保在生产环境中禁用调试输出
    void debugLog(const std::string& message) {
        #ifdef DEBUG
        std::cout << "[DEBUG] " << message << std::endl;
        #endif
    }
};

📂 文件组织

头文件规范

cpp
// user_manager.h
#ifndef USER_MANAGER_H_  // 防止重复包含
#define USER_MANAGER_H_

#include <string>       // 标准库头文件
#include <vector>
#include <memory>

#include "base/object.h"    // 项目内部头文件
#include "common/types.h"

namespace myapp {
namespace auth {

// 前向声明
class Database;
class Logger;

/**
 * @brief 用户管理器类
 */
class UserManager {
public:
    // 类型别名
    using UserId = int64_t;
    using UserList = std::vector<std::string>;
    
    // 构造函数和析构函数
    explicit UserManager(std::shared_ptr<Database> db);
    ~UserManager();
    
    // 禁用拷贝,允许移动
    UserManager(const UserManager&) = delete;
    UserManager& operator=(const UserManager&) = delete;
    UserManager(UserManager&&) = default;
    UserManager& operator=(UserManager&&) = default;
    
    // 公共接口
    bool createUser(const std::string& username, const std::string& password);
    UserId authenticateUser(const std::string& username, const std::string& password);
    
private:
    // 私有成员
    std::shared_ptr<Database> database_;
    std::unique_ptr<Logger> logger_;
    
    // 私有方法
    bool validateCredentials_(const std::string& username, const std::string& password);
};

}  // namespace auth
}  // namespace myapp

#endif  // USER_MANAGER_H_

实现文件规范

cpp
// user_manager.cpp
#include "auth/user_manager.h"

#include <algorithm>    // 标准库
#include <cassert>
#include <stdexcept>

#include "base/database.h"      // 项目头文件
#include "common/logger.h"
#include "common/crypto_utils.h"

namespace myapp {
namespace auth {

namespace {  // 匿名命名空间用于内部辅助函数

constexpr int kMinUsernameLength = 3;
constexpr int kMaxUsernameLength = 20;
constexpr int kMinPasswordLength = 8;

bool isValidUsername(const std::string& username) {
    if (username.length() < kMinUsernameLength || 
        username.length() > kMaxUsernameLength) {
        return false;
    }
    
    return std::all_of(username.begin(), username.end(), 
                      [](char c) { return std::isalnum(c) || c == '_'; });
}

}  // namespace

UserManager::UserManager(std::shared_ptr<Database> db) 
    : database_(std::move(db)),
      logger_(std::make_unique<Logger>("UserManager")) {
    assert(database_ != nullptr);
    logger_->info("UserManager initialized");
}

UserManager::~UserManager() {
    logger_->info("UserManager destroyed");
}

bool UserManager::createUser(const std::string& username, 
                           const std::string& password) {
    logger_->debug("Creating user: {}", username);
    
    // 输入验证
    if (!isValidUsername(username)) {
        logger_->warning("Invalid username: {}", username);
        return false;
    }
    
    if (password.length() < kMinPasswordLength) {
        logger_->warning("Password too short");
        return false;
    }
    
    // 检查用户是否已存在
    if (database_->userExists(username)) {
        logger_->warning("User already exists: {}", username);
        return false;
    }
    
    try {
        // 哈希密码
        std::string hashed_password = crypto::hashPassword(password);
        
        // 保存到数据库
        UserId user_id = database_->createUser(username, hashed_password);
        
        logger_->info("User created successfully: {} (ID: {})", username, user_id);
        return true;
        
    } catch (const std::exception& e) {
        logger_->error("Failed to create user {}: {}", username, e.what());
        return false;
    }
}

}  // namespace auth
}  // namespace myapp

🛡️ 代码质量规范

错误处理

cpp
// ✅ 良好的错误处理
class FileManager {
public:
    enum class ErrorCode {
        kSuccess,
        kFileNotFound,
        kPermissionDenied,
        kInsufficientSpace,
        kCorruptedData
    };
    
    struct Result {
        ErrorCode error_code;
        std::string error_message;
        
        bool isSuccess() const { return error_code == ErrorCode::kSuccess; }
    };
    
    // 使用结果类型而不是异常
    Result readFile(const std::string& filename, std::string& content) {
        if (filename.empty()) {
            return {ErrorCode::kFileNotFound, "Filename cannot be empty"};
        }
        
        std::ifstream file(filename);
        if (!file.is_open()) {
            return {ErrorCode::kFileNotFound, "Cannot open file: " + filename};
        }
        
        try {
            content = std::string(std::istreambuf_iterator<char>(file),
                                 std::istreambuf_iterator<char>());
            return {ErrorCode::kSuccess, ""};
        } catch (const std::exception& e) {
            return {ErrorCode::kCorruptedData, "Error reading file: " + std::string(e.what())};
        }
    }
    
    // 异常只用于真正的异常情况
    void writeFile(const std::string& filename, const std::string& content) {
        if (filename.empty()) {
            throw std::invalid_argument("Filename cannot be empty");
        }
        
        std::ofstream file(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Cannot create file: " + filename);
        }
        
        file << content;
        if (file.fail()) {
            throw std::runtime_error("Error writing to file: " + filename);
        }
    }
};

资源管理

cpp
// ✅ RAII资源管理
class DatabaseConnection {
public:
    explicit DatabaseConnection(const std::string& connection_string) {
        connection_ = openConnection(connection_string);
        if (!connection_) {
            throw std::runtime_error("Failed to connect to database");
        }
    }
    
    ~DatabaseConnection() {
        if (connection_) {
            closeConnection(connection_);
        }
    }
    
    // 禁用拷贝,允许移动
    DatabaseConnection(const DatabaseConnection&) = delete;
    DatabaseConnection& operator=(const DatabaseConnection&) = delete;
    
    DatabaseConnection(DatabaseConnection&& other) noexcept
        : connection_(std::exchange(other.connection_, nullptr)) {}
    
    DatabaseConnection& operator=(DatabaseConnection&& other) noexcept {
        if (this != &other) {
            if (connection_) {
                closeConnection(connection_);
            }
            connection_ = std::exchange(other.connection_, nullptr);
        }
        return *this;
    }
    
    void execute(const std::string& query) {
        if (!connection_) {
            throw std::runtime_error("No active connection");
        }
        // 执行查询
    }
    
private:
    void* connection_ = nullptr;  // 实际的连接句柄
    
    void* openConnection(const std::string& connection_string);
    void closeConnection(void* connection);
};

性能考虑

cpp
// ✅ 性能优化的代码
class StringProcessor {
public:
    // 避免不必要的拷贝
    std::vector<std::string> processStrings(const std::vector<std::string>& input) {
        std::vector<std::string> result;
        result.reserve(input.size());  // 预分配内存
        
        for (const auto& str : input) {  // 范围for循环,避免拷贝
            if (str.empty()) continue;
            
            result.emplace_back(transformString(str));  // 就地构造
        }
        
        return result;
    }
    
    // 移动语义
    void addString(std::string str) {  // 按值传递,支持移动
        if (str.empty()) return;
        
        strings_.emplace_back(std::move(str));  // 移动到容器
    }
    
    // 字符串视图避免拷贝
    bool containsSubstring(std::string_view text, std::string_view pattern) {
        return text.find(pattern) != std::string_view::npos;
    }
    
private:
    std::vector<std::string> strings_;
    
    std::string transformString(const std::string& input) {
        // 字符串变换逻辑
        std::string result;
        result.reserve(input.size() * 2);  // 预估结果大小
        
        for (char c : input) {
            if (std::isalpha(c)) {
                result += std::toupper(c);
            }
        }
        
        return result;
    }
};

总结

命名规范总结

  • 类名: PascalCase (UserAccount)
  • 函数名: camelCase (getUserName)
  • 变量名: snake_case (user_name)
  • 成员变量: snake_case + 下划线后缀 (user_name_)
  • 常量: k前缀 + PascalCase (kMaxSize)
  • 枚举值: k前缀 + PascalCase (kConnected)

格式规范要点

  • 缩进: 4个空格或1个Tab
  • 行长度: 建议不超过80-100字符
  • 括号: 推荐Allman或K&R风格,保持一致
  • 空格: 运算符周围添加空格
  • 空行: 逻辑块之间添加空行

注释规范要点

  • 文档注释: 使用Doxygen格式
  • 行内注释: 解释为什么,不是做什么
  • 特殊标记: TODO, FIXME, NOTE, WARNING
  • 代码自解释: 优秀的命名减少注释需求

代码质量要求

  • 错误处理: 明确的错误处理策略
  • 资源管理: 遵循RAII原则
  • 性能意识: 避免不必要的拷贝和分配
  • 线程安全: 明确标注线程安全性
  • 可测试性: 设计易于测试的接口

工具支持

  • 格式化: clang-format
  • 静态分析: clang-tidy, cppcheck
  • 文档生成: Doxygen
  • 代码审查: 集成到CI/CD流程

代码规范不仅是风格问题,更是代码质量和团队协作的基础。建立并遵循一致的代码规范能显著提升项目的可维护性和开发效率。

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