1. 理解C++中的万能工具:类和对象进阶
在C++编程中,类和对象就像瑞士军刀一样,是解决复杂问题的万能工具。当你掌握了基础语法后,如何真正发挥它们的威力?这就是我们今天要深入探讨的核心话题。
类和对象作为C++面向对象编程的基石,其强大之处在于能够将数据和对数据的操作封装在一起。想象一下,你正在开发一个图形处理程序。通过创建Image类,你可以把像素数据、尺寸信息等封装在对象内部,同时提供调整亮度、旋转等操作方法。这种封装性让代码更易维护和扩展。
提示:在实际项目中,良好的类设计应该像黑盒子一样,外部只需知道"做什么",而不需要关心"怎么做"。
2. 类的设计原则与最佳实践
2.1 访问控制:保护你的数据
C++提供了三种访问修饰符:public、protected和private。合理使用它们就像给你的数据上锁:
cpp复制class BankAccount {
private:
double balance; // 只有类内部可以访问
protected:
string accountNumber; // 派生类可以访问
public:
void deposit(double amount); // 任何人都可以调用
};
经验法则:
- 成员变量通常设为private
- 只在必要时使用protected
- public接口应该是最小且完备的
2.2 构造函数与析构函数:对象的生与死
构造函数和析构函数是类生命周期管理的关键。考虑这个文件处理类的例子:
cpp复制class FileHandler {
public:
FileHandler(const string& filename) {
file.open(filename);
if (!file.is_open()) {
throw runtime_error("无法打开文件");
}
}
~FileHandler() {
if (file.is_open()) {
file.close();
}
}
private:
fstream file;
};
注意:使用RAII(资源获取即初始化)技术可以避免资源泄漏,这是C++中异常安全编程的核心。
3. 类的进阶特性与应用
3.1 运算符重载:让类像内置类型一样工作
运算符重载可以让你的类使用起来更直观。比如实现一个复数类:
cpp复制class Complex {
public:
Complex(double r, double i) : real(r), imag(i) {}
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 输出运算符重载
friend ostream& operator<<(ostream& os, const Complex& c);
private:
double real, imag;
};
ostream& operator<<(ostream& os, const Complex& c) {
os << c.real << "+" << c.imag << "i";
return os;
}
3.2 静态成员:类的共享数据
静态成员属于类本身而非特定对象。它们常用于:
- 维护类级别的状态
- 实现单例模式
- 共享常量或工具函数
cpp复制class Logger {
public:
static Logger& getInstance() {
static Logger instance;
return instance;
}
void log(const string& message) {
// 记录日志
}
private:
Logger() {} // 私有构造函数
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
};
4. 面向对象设计模式实战
4.1 工厂模式:灵活创建对象
工厂模式将对象创建逻辑封装起来,使代码更灵活:
cpp复制class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {}
};
class Circle : public Shape { /*...*/ };
class Rectangle : public Shape { /*...*/ };
class ShapeFactory {
public:
static Shape* createShape(const string& type) {
if (type == "circle") return new Circle();
if (type == "rectangle") return new Rectangle();
return nullptr;
}
};
4.2 观察者模式:实现松耦合
观察者模式在GUI、事件处理等场景非常有用:
cpp复制class Observer {
public:
virtual void update() = 0;
};
class Subject {
public:
void attach(Observer* o) { observers.push_back(o); }
void notify() {
for (auto o : observers) o->update();
}
private:
vector<Observer*> observers;
};
5. 性能优化与高级技巧
5.1 移动语义:提升效率
C++11引入的移动语义可以避免不必要的拷贝:
cpp复制class Buffer {
public:
Buffer(size_t size) : data(new char[size]), size(size) {}
// 移动构造函数
Buffer(Buffer&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
~Buffer() { delete[] data; }
private:
char* data;
size_t size;
};
5.2 内联函数:减少函数调用开销
对于小型频繁调用的函数,使用inline可以提升性能:
cpp复制class MathUtils {
public:
inline static double square(double x) { return x * x; }
};
提示:现代编译器通常会自动决定是否内联,所以显式使用inline更多是给编译器的建议。
6. 常见陷阱与调试技巧
6.1 对象切片问题
当派生类对象被赋值给基类对象时,会发生对象切片:
cpp复制class Base { /*...*/ };
class Derived : public Base { /*...*/ };
Derived d;
Base b = d; // 切片发生,Derived特有部分丢失
解决方案:使用指针或引用,或者考虑虚函数和抽象基类。
6.2 内存管理问题
常见内存问题包括:
- 忘记释放内存
- 双重释放
- 访问已释放内存
使用智能指针可以避免大多数问题:
cpp复制#include <memory>
class Resource { /*...*/ };
void process() {
auto res = make_shared<Resource>();
// 不需要手动delete
}
7. 现代C++特性在类设计中的应用
7.1 constexpr与编译时计算
C++11引入的constexpr可以让某些计算在编译时完成:
cpp复制class Circle {
public:
constexpr Circle(double r) : radius(r) {}
constexpr double area() const { return PI * radius * radius; }
private:
double radius;
static constexpr double PI = 3.1415926;
};
7.2 类型推导与auto
现代C++中,auto可以简化代码:
cpp复制class Container {
public:
auto begin() -> decltype(data.begin()) {
return data.begin();
}
private:
vector<int> data;
};
8. 实战案例:设计一个简单的字符串类
让我们综合运用所学知识,实现一个简化版的字符串类:
cpp复制class MyString {
public:
// 构造函数
MyString(const char* str = "") {
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
}
// 拷贝构造函数
MyString(const MyString& other) {
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
}
// 移动构造函数
MyString(MyString&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
// 析构函数
~MyString() {
delete[] data;
}
// 赋值运算符
MyString& operator=(const MyString& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
}
return *this;
}
// 移动赋值运算符
MyString& operator=(MyString&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
return *this;
}
// 拼接运算符
MyString operator+(const MyString& other) const {
MyString result;
result.size = size + other.size;
result.data = new char[result.size + 1];
strcpy(result.data, data);
strcat(result.data, other.data);
return result;
}
// 输出运算符
friend ostream& operator<<(ostream& os, const MyString& str) {
os << str.data;
return os;
}
private:
char* data;
size_t size;
};
这个实现展示了:
- 资源管理(RAII)
- 拷贝控制(三/五法则)
- 运算符重载
- 移动语义
9. 测试与调试你的类
设计好类后,全面的测试至关重要。考虑以下测试用例:
cpp复制void testMyString() {
// 基本构造测试
MyString s1("Hello");
MyString s2(" World");
// 拷贝构造测试
MyString s3 = s1;
// 移动构造测试
MyString s4 = std::move(s1);
// 运算符测试
MyString s5 = s3 + s2;
// 赋值测试
MyString s6;
s6 = s5;
// 移动赋值测试
MyString s7;
s7 = std::move(s6);
cout << "s3: " << s3 << endl;
cout << "s4: " << s4 << endl;
cout << "s5: " << s5 << endl;
cout << "s7: " << s7 << endl;
}
提示:使用单元测试框架如Google Test可以更系统地组织测试用例。
10. 类设计的扩展思考
在实际项目中,类设计还需要考虑:
- 异常安全:确保操作失败时资源不被泄漏
- 线程安全:多线程环境下的正确性
- 序列化:对象的持久化存储
- 接口设计:保持接口稳定且易于使用
- 性能考量:热点路径的优化
例如,线程安全的计数器实现:
cpp复制#include <mutex>
class ThreadSafeCounter {
public:
void increment() {
lock_guard<mutex> lock(mtx);
++count;
}
int get() const {
lock_guard<mutex> lock(mtx);
return count;
}
private:
mutable mutex mtx;
int count = 0;
};
11. 工具与资源推荐
提升类设计能力的实用工具:
-
静态分析工具:
- Clang-Tidy
- Cppcheck
- PVS-Studio
-
性能分析工具:
- Valgrind
- Google Benchmark
- Intel VTune
-
设计工具:
- UML工具(如PlantUML)
- Doxygen(文档生成)
-
学习资源:
- 《Effective C++》系列
- 《C++ Core Guidelines》
- CppReference.com
12. 从类到大型项目
当项目规模扩大时,需要考虑:
- 模块划分:合理组织类和命名空间
- 依赖管理:减少编译依赖(PIMPL模式)
- 构建系统:使用CMake等现代构建工具
- 代码规范:保持一致的编码风格
例如,使用PIMPL模式减少编译依赖:
cpp复制// Widget.h
class Widget {
public:
Widget();
~Widget();
void doSomething();
private:
class Impl;
unique_ptr<Impl> pImpl;
};
// Widget.cpp
class Widget::Impl {
// 实现细节
};
Widget::Widget() : pImpl(make_unique<Impl>()) {}
Widget::~Widget() = default;
void Widget::doSomething() { pImpl->doSomething(); }
13. 持续学习与实践建议
掌握类和对象需要不断实践:
- 阅读优秀代码:如标准库实现、开源项目
- 参与开源项目:实际项目经验最宝贵
- 代码审查:学习他人的设计思路
- 重构练习:改进现有代码的设计
- 设计模式学习:理解常见解决方案
一个实用的学习路径:
- 掌握基础语法和语义
- 理解设计原则(SOLID等)
- 学习常见设计模式
- 研究标准库设计
- 参与实际项目开发
14. 性能与可维护性的平衡
在设计类时,经常需要在性能和可维护性之间权衡:
- 内联小函数 vs 清晰的接口
- 内存池优化 vs 简单的new/delete
- 模板元编程 vs 运行时多态
- 数据局部性优化 vs 清晰的抽象
例如,考虑一个游戏中的粒子系统:
cpp复制// 版本1:清晰但可能低效
class Particle {
public:
virtual void update() = 0;
virtual void render() = 0;
};
// 版本2:高效但更复杂
class ParticleSystem {
public:
void updateAll() {
// 批量处理所有粒子
}
void renderAll() {
// 批量渲染所有粒子
}
private:
vector<Position> positions;
vector<Velocity> velocities;
// 其他数据...
};
15. 现代C++中的类设计趋势
C++17/20带来的新特性影响类设计:
- 结构化绑定:方便处理多个返回值
- 概念(Concepts):更好的模板约束
- 协程(Coroutines):异步编程新模式
- 模块(Modules):改进的代码组织方式
例如,使用概念约束模板类:
cpp复制template<typename T>
concept Arithmetic = is_arithmetic_v<T>;
template<Arithmetic T>
class Vector {
// 只能用于算术类型
};
16. 跨平台开发的类设计考量
编写跨平台代码时需要注意:
- 数据类型大小:使用固定大小类型如int32_t
- 字节序:网络传输时处理字节序转换
- 系统API差异:使用工厂模式封装平台特定代码
- 路径处理:使用filesystem库处理路径差异
例如,跨平台文件处理:
cpp复制class File {
public:
static unique_ptr<File> create(const string& path);
virtual ~File() = default;
virtual void read(void* buffer, size_t size) = 0;
virtual void write(const void* buffer, size_t size) = 0;
};
// 平台特定实现
#ifdef _WIN32
class WindowsFile : public File { /*...*/ };
#else
class UnixFile : public File { /*...*/ };
#endif
17. 类设计中的设计模式应用
常见设计模式在类设计中的应用场景:
- 策略模式:运行时选择算法
- 装饰器模式:动态添加功能
- 代理模式:控制对象访问
- 状态模式:根据状态改变行为
例如,策略模式的实现:
cpp复制class SortStrategy {
public:
virtual void sort(vector<int>& data) = 0;
};
class QuickSort : public SortStrategy { /*...*/ };
class MergeSort : public SortStrategy { /*...*/ };
class Sorter {
public:
void setStrategy(unique_ptr<SortStrategy> strategy) {
this->strategy = move(strategy);
}
void sort(vector<int>& data) {
strategy->sort(data);
}
private:
unique_ptr<SortStrategy> strategy;
};
18. 模板与泛型编程在类设计中的应用
模板可以创建高度可复用的类:
cpp复制template<typename T, size_t N>
class FixedArray {
public:
T& operator[](size_t index) {
if (index >= N) throw out_of_range("索引越界");
return data[index];
}
size_t size() const { return N; }
private:
T data[N];
};
高级技巧:CRTP(奇异递归模板模式)
cpp复制template<typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() {
// 具体实现
}
};
19. 类设计中的内存管理进阶
除了智能指针,还有其他内存管理技术:
- 内存池:减少动态分配开销
- 自定义分配器:优化特定场景
- 对象池:重用对象减少构造/析构开销
例如,简单的对象池实现:
cpp复制template<typename T>
class ObjectPool {
public:
template<typename... Args>
shared_ptr<T> acquire(Args&&... args) {
if (pool.empty()) {
return make_shared<T>(forward<Args>(args)...);
}
auto obj = move(pool.back());
pool.pop_back();
*obj = T(forward<Args>(args)...); // 重用内存
return shared_ptr<T>(obj.release(), [this](T* p) {
pool.push_back(unique_ptr<T>(p));
});
}
private:
vector<unique_ptr<T>> pool;
};
20. 元编程在类设计中的应用
C++模板元编程可以创建在编译时计算的类:
cpp复制template<size_t N>
struct Factorial {
static const size_t value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
static const size_t value = 1;
};
// 使用
constexpr auto fact5 = Factorial<5>::value; // 编译时计算120
C++17的if constexpr简化元编程:
cpp复制template<typename T>
auto process(T value) {
if constexpr (is_integral_v<T>) {
return value * 2;
} else if constexpr (is_floating_point_v<T>) {
return value / 2;
} else {
static_assert(false, "不支持的类型");
}
}
21. 类设计中的并发考量
多线程环境下的类设计需要特别小心:
-
线程安全级别:
- 不可变对象(最安全)
- 线程安全类(内部同步)
- 条件线程安全(需要外部同步)
- 非线程安全(最常见)
-
避免死锁:按固定顺序获取锁
-
减少锁竞争:细粒度锁或无锁数据结构
例如,线程安全的队列:
cpp复制template<typename T>
class ThreadSafeQueue {
public:
void push(T value) {
lock_guard<mutex> lock(mtx);
data.push(move(value));
cond.notify_one();
}
bool try_pop(T& value) {
lock_guard<mutex> lock(mtx);
if (data.empty()) return false;
value = move(data.front());
data.pop();
return true;
}
void wait_and_pop(T& value) {
unique_lock<mutex> lock(mtx);
cond.wait(lock, [this]{ return !data.empty(); });
value = move(data.front());
data.pop();
}
private:
mutex mtx;
condition_variable cond;
queue<T> data;
};
22. 类设计的可测试性
易于测试的类通常具有:
- 清晰的单一职责
- 最小化依赖(特别是全局状态)
- 依赖注入支持
- 虚函数钩子用于测试
例如,考虑一个依赖数据库的类:
cpp复制class Database {
public:
virtual ~Database() = default;
virtual User getUser(int id) = 0;
};
class RealDatabase : public Database { /*...*/ };
class MockDatabase : public Database {
public:
User getUser(int id) override {
return User{"Test", id}; // 返回测试数据
}
};
class UserService {
public:
UserService(unique_ptr<Database> db) : db(move(db)) {}
string getUserName(int id) {
return db->getUser(id).name;
}
private:
unique_ptr<Database> db;
};
23. 类设计的文档化
良好的文档应包括:
- 接口契约:前置条件、后置条件、异常
- 线程安全说明
- 性能特征:时间复杂度、空间复杂度
- 使用示例
Doxygen注释示例:
cpp复制/**
* @class ThreadPool
* @brief 线程池实现,用于并发执行任务
*
* 线程池在构造时创建固定数量的工作线程,
* 任务通过enqueue方法提交,由工作线程执行
*
* @note 所有方法都是线程安全的
*/
class ThreadPool {
public:
/**
* @brief 提交任务到线程池
* @tparam F 可调用对象类型
* @param f 要执行的可调用对象
* @return std::future获取执行结果
* @throws std::runtime_error 如果线程池已停止
*/
template<typename F>
auto enqueue(F&& f) -> std::future<decltype(f())> {
// 实现...
}
};
24. 类设计的演化与重构
随着需求变化,类设计也需要不断调整:
-
识别代码异味:
- 过大的类
- 过长的函数
- 过多的参数
- 频繁的变更
-
重构技巧:
- 提取方法
- 提取类
- 引入参数对象
- 用策略替换条件
例如,重构前的类:
cpp复制class ReportGenerator {
public:
void generate(string format) {
if (format == "HTML") {
// 生成HTML报告
} else if (format == "PDF") {
// 生成PDF报告
} // 更多格式...
}
};
重构后:
cpp复制class ReportGenerator {
public:
void generate(unique_ptr<ReportFormat> format) {
format->generate(this);
}
};
class ReportFormat {
public:
virtual void generate(ReportGenerator* report) = 0;
};
class HTMLFormat : public ReportFormat { /*...*/ };
class PDFFormat : public ReportFormat { /*...*/ };
25. 类设计中的异常处理策略
设计异常安全的类需要考虑:
- 基本保证:异常发生后对象仍可用
- 强保证:操作要么完全成功,要么状态不变
- 不抛保证:操作承诺不抛出异常
例如,实现强保证的swap:
cpp复制class ResourceHolder {
public:
void swap(ResourceHolder& other) noexcept {
using std::swap;
swap(resource, other.resource);
}
ResourceHolder& operator=(ResourceHolder other) noexcept {
swap(other);
return *this;
}
private:
Resource* resource;
};
26. 类设计中的性能优化技巧
- 小对象优化:避免频繁堆分配
- 热路径优化:内联关键函数
- 缓存友好设计:提高数据局部性
- 延迟初始化:推迟昂贵操作
例如,小对象优化实现:
cpp复制class SmallString {
static const size_t LocalSize = 16;
union {
char local[LocalSize];
struct {
char* data;
size_t size;
size_t capacity;
} heap;
};
bool isLocal() const {
return heap.size <= LocalSize;
}
public:
// 接口实现...
};
27. 类设计中的调试支持
为便于调试,可以添加:
- 对象标识:唯一ID或名称
- 状态检查:验证对象有效性
- 日志记录:关键操作跟踪
- 自定义断言:运行时检查
例如:
cpp复制class Debuggable {
public:
Debuggable(string name) : name(move(name)), id(nextId++) {}
void log(const string& msg) const {
cerr << "[" << name << "#" << id << "] " << msg << endl;
}
void checkInvariant() const {
if (!isValid()) {
log("违反不变条件");
throw runtime_error("对象状态无效");
}
}
private:
string name;
int id;
static int nextId;
virtual bool isValid() const = 0;
};
28. 类设计中的跨语言互操作
与其他语言交互时考虑:
- C接口:extern "C"函数
- 名称修饰:避免混淆
- 内存管理:明确所有权
- 异常转换:C++异常到错误码
例如,导出到C的接口:
cpp复制// C++实现
class ImageProcessor { /*...*/ };
extern "C" {
ImageProcessor* create_processor() {
try {
return new ImageProcessor();
} catch (...) {
return nullptr;
}
}
void process_image(ImageProcessor* p) {
try {
p->process();
} catch (...) {
// 转换为错误码
}
}
}
29. 类设计中的模式识别与选择
常见场景的模式选择:
- 创建对象:工厂、建造者、原型
- 结构组织:适配器、桥接、组合
- 行为控制:命令、中介者、观察者
- 性能优化:享元、对象池
例如,使用建造者模式创建复杂对象:
cpp复制class Query {
// 复杂对象
friend class QueryBuilder;
Query() = default;
public:
// 使用构建器创建
static QueryBuilder create();
};
class QueryBuilder {
public:
QueryBuilder& withFilter(string filter) {
this->filter = move(filter);
return *this;
}
Query build() {
Query q;
q.filter = move(filter);
// 设置其他属性
return q;
}
private:
string filter;
};
30. 类设计的未来趋势与思考
C++的持续演进带来新可能:
- 概念(Concepts):更清晰的模板约束
- 协程(Coroutines):简化异步代码
- 反射(Reflection):运行时类型信息
- 模式匹配:更强大的条件处理
例如,协程在类设计中的应用:
cpp复制class AsyncTask {
public:
struct promise_type {
AsyncTask get_return_object() { return {}; }
suspend_never initial_suspend() { return {}; }
suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { terminate(); }
};
};
AsyncTask fetchData() {
co_await httpRequest("example.com");
// 处理数据
}
31. 类设计中的资源管理策略
除了内存,其他资源也需要妥善管理:
- 文件句柄:使用RAII包装器
- 网络连接:确保正确关闭
- 图形资源:及时释放
- 锁:避免死锁
例如,文件RAII包装:
cpp复制class File {
public:
File(const string& path, const string& mode) {
handle = fopen(path.c_str(), mode.c_str());
if (!handle) throw runtime_error("无法打开文件");
}
~File() {
if (handle) fclose(handle);
}
// 禁用拷贝
File(const File&) = delete;
File& operator=(const File&) = delete;
// 允许移动
File(File&& other) noexcept : handle(other.handle) {
other.handle = nullptr;
}
File& operator=(File&& other) noexcept {
if (this != &other) {
if (handle) fclose(handle);
handle = other.handle;
other.handle = nullptr;
}
return *this;
}
void write(const string& data) {
if (fwrite(data.data(), 1, data.size(), handle) != data.size()) {
throw runtime_error("写入失败");
}
}
private:
FILE* handle = nullptr;
};
32. 类设计中的类型安全技巧
增强类型安全可以避免许多错误:
- 强类型定义:避免原始类型混淆
- enum class:限定作用域枚举
- 用户定义字面量:类型安全的常量
- 标记结构:区分相同类型的参数
例如,使用强类型定义:
cpp复制class Meter {
public:
explicit Meter(double value) : value(value) {}
double get() const { return value; }
private:
double value;
};
class Second {
public:
explicit Second(double value) : value(value) {}
double get() const { return value; }
private:
double value;
};
class Speed {
public:
static Speed calculate(Meter distance, Second time) {
return Speed(distance.get() / time.get());
}
private:
Speed(double value) : value(value) {}
double value;
};
33. 类设计中的缓存策略
合理的缓存可以显著提升性能:
- LRU缓存:最近最少使用
- 写回缓存:延迟写入
- 预取:提前加载可能需要的资源
- 多级缓存:分层存储
例如,简单的LRU缓存实现:
cpp复制template<typename Key, typename Value>
class LRUCache {
public:
explicit LRUCache(size_t capacity) : capacity(capacity) {}
optional<Value> get(const Key& key) {
auto it = cache.find(key);
if (it == cache.end()) return nullopt;
// 移动到最近使用位置
lru.splice(lru.begin(), lru, it->second);
return it->second->second;
}
void put(const Key& key, const Value& value) {
auto it = cache.find(key);
if (it != cache.end()) {
it->second->second = value;
lru.splice(lru.begin(), lru, it->second);
return;
}
if (cache.size() >= capacity) {
// 移除最久未使用
cache.erase(lru.back().first);
lru.pop_back();
}
lru.emplace_front(key, value);
cache[key] = lru.begin();
}
private:
size_t capacity;
list<pair<Key, Value>> lru;
unordered_map<Key, typename list<pair<Key, Value>>::iterator> cache;
};
34. 类设计中的算法封装
将常用算法封装为类可以提高复用性:
- 排序策略:封装不同排序算法
- 搜索算法:提供统一接口
- 图算法:封装DFS、BFS等
- 数值计算:矩阵运算、统计等
例如,排序策略封装:
cpp复制class SortAlgorithm {
public:
virtual ~SortAlgorithm() = default;
virtual void sort(vector<int>& data) = 0;
};
class QuickSort : public SortAlgorithm {
public:
void sort(vector<int>& data) override {
// 快速排序实现
}
};
class MergeSort : public SortAlgorithm {
public:
void sort(vector<int>& data) override {
// 归并排序实现
}
};
class Sorter {
public:
explicit Sorter(unique_ptr<SortAlgorithm> algo)
: algo(move(algo)) {}
void sort(vector<int>& data) {
algo->sort(data);
}
private:
unique_ptr<SortAlgorithm> algo;
};
35. 类设计中的事件处理机制
事件驱动系统中的类设计:
- 事件定义:明确事件类型和数据
- 事件分发:高效路由事件
- 事件处理:注册回调或监听器
- 异步事件:处理跨线程事件
例如,简单的事件系统:
cpp复制class Event {
public:
virtual ~Event() = default;
virtual string type() const = 0;
};
class EventDispatcher {
public:
using Handler = function<void(const Event&)>;
void addListener(const string& type, Handler handler) {
listeners[type].push_back(move(handler));
}
void dispatch(const Event& event) {
auto it = listeners.find(event.type());
if (it != listeners.end()) {
for (auto& handler : it->second) {
handler(event);
}
}
}
private:
unordered_map<string, vector<Handler>> listeners;
};
// 使用
class MouseEvent : public Event {
public:
string type() const override { return "mouse"; }
};
dispatcher.addListener("mouse", [](const Event& e) {
cout << "处理鼠标事件" << endl;
});
36. 类设计中的插件系统架构
支持插件的系统需要考虑:
- 插件接口:定义插件必须实现的接口
- 加载机制:动态加载共享库
- 生命周期管理:初始化和清理
- 跨版本兼容:接口版本控制
例如,简单的插件系统:
cpp复制class Plugin {
public:
virtual ~Plugin() = default;
virtual string name() const = 0;
virtual void initialize() = 0;
virtual void execute() = 0;
};
class PluginManager {
public:
void load(const string& path) {
auto handle = dlopen(path.c_str(), RTLD_LAZY);
if (!handle) throw runtime_error(dlerror());
auto create = reinterpret_cast<Plugin*(*)()>(
dlsym(handle, "createPlugin"));
if (!create) throw runtime_error(dlerror());
plugins.emplace_back(unique_ptr<Plugin>(create()));
}
void runAll() {
for (auto& plugin : plugins) {
plugin->execute();
}
}
private:
vector<unique_ptr<Plugin>> plugins;
};
// 插件实现
extern "C" Plugin* createPlugin() {
return new MyPlugin();
}
37. 类设计中的状态管理
复杂状态机的类实现方式:
- 状态模式:每个状态一个类
- 表驱动:状态转换表
- 行为树:AI常用状态管理
- 栈式状态:如游戏中的菜单系统
例如,状态模式实现:
cpp复制class State {
public:
virtual ~State() = default;
virtual void enter() = 0;
virtual void exit() = 0;
virtual void update() = 0;
};
class IdleState : public State { /*...*/ };
class RunningState : public State { /*...*/ };
class StateMachine {
public:
void changeState(unique_ptr<State> newState) {
if (current) current->exit();
current = move(newState);
current->enter();
}
void update() {
if (current) current->update();
}
private:
unique_ptr<State> current;
};
38. 类设计中的序列化支持
对象序列化需要考虑:
- 格式选择:JSON、二进制、XML等
- 版本控制:兼容旧版本数据
- 指针处理:对象引用关系
- 平台兼容:字节序、对齐等
例如,简单的序列化接口:
cpp复制class Serializable {
public:
virtual ~Serializable() = default;
virtual void serialize(ostream& out) const = 0;
virtual void deserialize(istream& in) = 0;
};
class User : public Serializable {
public:
void serialize(ostream& out) const override {
out << name << "\n" << age << "\n";
}
void deserialize(istream& in) override {
getline(in, name);
