2、c++特性概述
约 1615 字大约 5 分钟
2026-03-23
友元
https://jishuzhan.net/article/1816013892325740545可以存在的函数
普通成员函数
const成员函数
class MyClass {
private:
int data;
mutable int cache; // mutable成员即使在const函数中也可修改
public:
// const成员函数 - 不修改对象状态(除了mutable成员)
int getData() const {
cache++; // ✅ 可以修改mutable成员
// data++; // ❌ 错误!不能修改普通成员
return data;
}
// 非const成员函数
void setData(int d) {
data = d; // ✅ 可以修改
}
// const和non-const重载
const int& operator[](int index) const { return data; } // 用于const对象
int& operator[](int index) { return data; } // 用于非const对象
};静态成员函数
class MyClass {
private:
static int totalCount; // 静态成员变量
int instanceId;
public:
MyClass() {
instanceId = ++totalCount;
}
// 静态成员函数
static int getTotalCount() {
// 只能访问静态成员
return totalCount;
// return instanceId; // ❌ 错误!不能访问非静态成员
}
// 静态成员函数不能是const(因为static不属于某个对象)
// static void func() const; // ❌ 错误!
};
int MyClass::totalCount = 0;默认构造函数【编译器会自动生成】
拷贝构造函数
class MyClass {
private:
int* data;
size_t size;
public:
// 拷贝构造函数
MyClass(const MyClass& other) : size(other.size) {
cout << "Copy constructor" << endl;
data = new int[size];
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i]; // 深拷贝
}
}
// 拷贝构造函数可以被删除
MyClass(const MyClass&) = delete;
};移动构造函数
移动构造函数可以优化对象复制的性能
class MyClass {
private:
int* data;
size_t size;
public:
// 移动构造函数
MyClass(MyClass&& other) noexcept
: data(other.data), size(other.size) {
cout << "Move constructor" << endl;
other.data = nullptr; // 源对象置空
other.size = 0;
}
};| 特性 | 拷贝构造函数 | 移动构造函数 |
|---|---|---|
| 语法 | LevelNode(const LevelNode&) | LevelNode(LevelNode&&) |
| 参数类型 | const左值引用 | 右值引用 |
| 源对象状态 | 保持不变 | 被修改(资源被偷走) |
| 性能 | 慢(深拷贝) | 快(指针转移) |
| 异常安全 | 强(原对象不变) | 弱(原对象被修改) |
| 使用场景 | 需要保留原对象 | 原对象即将销毁 |
拷贝赋值运算符
class MyClass {
private:
int* data;
size_t size;
public:
// 拷贝赋值运算符
MyClass& operator=(const MyClass& other) {
cout << "Copy assignment operator" << endl;
if (this != &other) { // 自赋值检查
// 先分配新资源
int* newData = new int[other.size];
for (size_t i = 0; i < other.size; i++) {
newData[i] = other.data[i];
}
// 释放旧资源
delete[] data;
// 赋值
data = newData;
size = other.size;
}
return *this; // 返回自身引用
}
};移动赋值运算符(C++11)
class MyClass {
private:
int* data;
size_t size;
public:
// 移动赋值运算符
MyClass& operator=(MyClass&& other) noexcept {
cout << "Move assignment operator" << endl;
if (this != &other) {
delete[] data; // 释放自己的资源
data = other.data; // 偷取对方的资源
size = other.size;
other.data = nullptr; // 对方置空
other.size = 0;
}
return *this;
}
};析构函数
class MyClass {
private:
int* data;
public:
MyClass() {
data = new int[100];
}
// 析构函数
~MyClass() {
cout << "Destructor" << endl;
delete[] data; // 释放资源
}
// 虚析构函数(用于多态基类)
virtual ~MyClass() = default;
};运算符重载函数
总结
| 类别 | 函数类型 | 主要特点 |
|---|---|---|
| 基础函数 | 普通成员函数 | 可访问所有成员,有this指针 |
| const成员函数 | 不修改对象状态(mutable除外) | |
| static成员函数 | 无this指针,只能访问static成员 | |
| 特殊函数 | 构造函数 | 对象创建时调用 |
| 析构函数 | 对象销毁时调用 | |
| 拷贝构造/赋值 | 深拷贝资源 | |
| 移动构造/赋值 | 转移资源所有权 | |
| 运算符重载 | 算术运算符 | +, -, *, /等 |
| 比较运算符 | ==, <, >等 | |
| 下标运算符 | [] | |
| 函数调用运算符 | () | |
| 类型转换运算符 | operator T() | |
| 多态相关 | 虚函数 | 动态绑定 |
| 纯虚函数 | 抽象接口 | |
| final函数 | 禁止重写 | |
| 特殊用途 | 友元函数 | 访问私有成员 |
| 内联函数 | 减少调用开销 | |
| constexpr函数 | 编译时计算 | |
| 委托构造函数 | 构造函数复用 | |
| noexcept函数 | 异常规范 | |
| C++20+ | 三路比较 | <=>运算符 |
| consteval | 强制编译时执行 |
拷贝赋值和移动赋值的区别
| 特性 | 拷贝赋值 | 移动赋值 |
|---|---|---|
| 签名 | operator=(const Order&) | operator=(Order&&) |
| 参数类型 | const左值引用 | 右值引用 |
| 源对象状态 | 保持不变 | 被修改(置空) |
| 资源处理 | 深拷贝 | 资源转移 |
| 性能 | 可能较慢(需要分配资源) | 通常很快(指针交换) |
c++项目的组织结构
// 项目结构示例
project/
├── include/
│ ├── Math/
│ │ ├── Vector3.h // 接口声明
│ │ ├── Vector3.inl // 内联实现
│ │ ├── Matrix4.h
│ │ └── Matrix4.inl
│ └── Game/
│ ├── Player.h
│ └── Player.inl
└── src/
├── Math/
│ └── Vector3.cpp // 非内联函数实现
└── Game/
└── Player.cpp避免ODR违反的核心要点
| 场景 | 正确做法 |
|---|---|
| 非内联函数 | 在.h中声明,在.cpp中定义 |
| 内联函数 | 在.h或.inl中定义(使用inline关键字) |
| 模板 | 全部放在.h或.inl中(隐式inline) |
| 全局变量 | 使用extern声明,在一个.cpp中定义;或使用inline变量(C++17) |
| 静态成员 | 在类内声明,在一个.cpp中定义 |
| const变量 | 可以在头文件中定义(有内部链接) |
使用.inl文件的优势:
- ✅ 将接口和实现分离
- ✅ 使用inline避免ODR违反
- ✅ 保持头文件清晰
- ✅ 便于管理模板和内联函数
- ✅ 提高编译速度
c++中assert关键字
assert 是 C/C++ 中的一个运行时断言宏,用于在调试阶段检查"应该永远为真"的条件。
基本用法
#include <cassert> // C++ 方式
// 或 #include <assert.h> // C 方式
int divide(int a, int b) {
assert(b != 0); // 如果 b == 0,程序终止
return a / b;
}
int main() {
divide(10, 2); // OK
divide(10, 0); // ❌ 触发 assert
return 0;
}assert vs 异常处理
| 特性 | assert | 异常 |
|---|---|---|
| 目的 | 调试时检查程序错误 | 处理运行时异常情况 |
| 生效范围 | 调试模式(NDEBUG未定义) | 所有模式 |
| 行为 | 终止程序 | 可捕获并恢复 |
| 适用场景 | 永远不应该发生的错误 | 可预见的异常情况 |
| 性能影响 | 调试模式有开销,发布模式无 | 始终有开销 |
- assert 是调试工具,用于检查"永远为真"的条件
- 在发布模式(NDEBUG)下完全移除,无性能开销
- 用于捕获程序错误,而不是处理用户输入或运行时异常
- 静态断言(static_assert)用于编译时检查
- 在金融/交易系统(如你的 OrderBook)中,assert 常用于检查数据一致性和不变量
应该使用 assert 的场景
- 检查函数参数的合法性(私有函数)
- 检查类的不变式
- 检查算法的预期结果
- 验证"不可能发生"的情况