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