
在 C++ 面向对象编程中,句柄类 (Handle Class) 是一种强大的设计模式,它允许我们以统一的接口操作不同类型的对象,同时隐藏对象的具体实现细节。结合继承和多态机制,句柄类可以实现灵活的对象管理,尤其适用于需要处理多种派生类对象的场景。
句柄类是一种包装类,它封装了对另一个对象 (通常是基类指针) 的访问。句柄类的主要作用是提供一个统一的接口,隐藏底层对象的具体类型和实现细节,同时允许通过多态机制操作不同的派生类对象。
一个典型的句柄类包含以下部分:
class Handle {
private:
Base* ptr; // 指向基类的指针
public:
// 构造函数
Handle(Base* p) : ptr(p) {}
// 析构函数
~Handle() { delete ptr; }
// 拷贝构造函数
Handle(const Handle& other);
// 赋值运算符
Handle& operator=(const Handle& other);
// 转发调用到底层对象
void callMethod() { ptr->method(); }
};最常见的句柄类实现方式是通过指针管理底层对象。这种方式允许句柄类在运行时动态绑定到不同的派生类对象。
class Base {
public:
virtual void print() const = 0;
virtual ~Base() {}
};
class Derived1 : public Base {
public:
void print() const override { std::cout << "Derived1" << std::endl; }
};
class Derived2 : public Base {
public:
void print() const override { std::cout << "Derived2" << std::endl; }
};
class Handle {
private:
Base* ptr;
public:
// 构造函数
Handle(Base* p) : ptr(p) {}
// 析构函数
~Handle() { delete ptr; }
// 拷贝构造函数 - 深拷贝
Handle(const Handle& other) {
if (other.ptr) {
ptr = other.ptr->clone(); // 假设Base定义了纯虚函数clone()
} else {
ptr = nullptr;
}
}
// 赋值运算符
Handle& operator=(const Handle& other) {
if (this != &other) {
delete ptr;
if (other.ptr) {
ptr = other.ptr->clone();
} else {
ptr = nullptr;
}
}
return *this;
}
// 转发调用
void print() const {
if (ptr) ptr->print();
}
};值语义的句柄类在复制时会创建底层对象的副本,而不是简单地复制指针。这种方式提供了更直观的对象行为,但需要确保底层对象支持复制操作。
class ValueHandle {
private:
std::unique_ptr<Base> ptr; // 使用智能指针管理内存
public:
// 构造函数
template<typename T>
ValueHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}
// 拷贝构造函数 - 深拷贝
ValueHandle(const ValueHandle& other) {
if (other.ptr) {
ptr = other.ptr->clone(); // 调用虚函数clone()创建副本
}
}
// 移动构造函数
ValueHandle(ValueHandle&& other) noexcept = default;
// 赋值运算符
ValueHandle& operator=(ValueHandle other) {
swap(*this, other);
return *this;
}
// 交换函数
friend void swap(ValueHandle& a, ValueHandle& b) noexcept {
using std::swap;
swap(a.ptr, b.ptr);
}
// 转发调用
void print() const {
if (ptr) ptr->print();
}
};引用计数的句柄类通过维护一个引用计数来管理底层对象的生命周期,当最后一个引用被销毁时才释放对象。
class RefCountHandle {
private:
Base* ptr;
int* count; // 引用计数
void acquire() {
if (ptr) ++(*count);
}
void release() {
if (ptr) {
if (--(*count) == 0) {
delete ptr;
delete count;
}
}
}
public:
// 构造函数
RefCountHandle(Base* p = nullptr) : ptr(p), count(new int(1)) {}
// 拷贝构造函数
RefCountHandle(const RefCountHandle& other) : ptr(other.ptr), count(other.count) {
acquire();
}
// 赋值运算符
RefCountHandle& operator=(const RefCountHandle& other) {
if (this != &other) {
release();
ptr = other.ptr;
count = other.count;
acquire();
}
return *this;
}
// 析构函数
~RefCountHandle() {
release();
}
// 转发调用
void print() const {
if (ptr) ptr->print();
}
};句柄类可以用于实现多态容器,允许在同一个容器中存储不同类型的对象。
#include <iostream>
#include <vector>
#include <memory>
// 手动实现make_unique
#if __cplusplus < 201402L
namespace std {
template<typename T, typename... Args>
unique_ptr<T> make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif
class Shape {
public:
virtual double area() const = 0;
virtual ~Shape() {}
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return 3.14 * radius * radius; }
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override { return width * height; }
};
// 句柄类
class ShapeHandle {
private:
std::unique_ptr<Shape> ptr;
public:
template<typename T>
ShapeHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}
double area() const { return ptr->area(); }
};
// 使用句柄类的多态容器
int main() {
std::vector<ShapeHandle> shapes;
shapes.emplace_back(Circle(5.0));
shapes.emplace_back(Rectangle(3.0, 4.0));
for (const auto& shape : shapes) {
std::cout << "Area: " << shape.area() << std::endl;
}
return 0;
}
句柄类可以用于实现插件系统,允许程序在运行时动态加载和使用不同的插件。
// 插件接口
class Plugin {
public:
virtual void execute() = 0;
virtual ~Plugin() {}
};
// 插件管理器
class PluginManager {
private:
std::vector<std::unique_ptr<Plugin>> plugins;
public:
// 加载插件
template<typename T>
void loadPlugin() {
plugins.push_back(std::make_unique<T>());
}
// 执行所有插件
void executeAll() {
for (const auto& plugin : plugins) {
plugin->execute();
}
}
};句柄类可以用于实现状态模式,允许对象在不同状态之间切换,而不需要修改对象的接口。
// 状态接口
class State {
public:
virtual void handle() = 0;
virtual ~State() {}
};
// 具体状态
class ConcreteStateA : public State {
public:
void handle() override { std::cout << "Handling state A" << std::endl; }
};
class ConcreteStateB : public State {
public:
void handle() override { std::cout << "Handling state B" << std::endl; }
};
// 上下文类
class Context {
private:
std::unique_ptr<State> state;
public:
Context() : state(std::make_unique<ConcreteStateA>()) {}
void setState(std::unique_ptr<State> newState) {
state = std::move(newState);
}
void request() {
state->handle();
}
};句柄类必须正确处理复制控制(拷贝构造函数、赋值运算符和析构函数),以确保对象的生命周期得到正确管理。根据需求,可以实现深拷贝、引用计数或禁止复制。
句柄类的操作应该是异常安全的,特别是在涉及动态内存分配和资源管理时。
使用句柄类时,需要确保基类定义了适当的虚函数,以便实现多态调用。
句柄类的接口应该简洁明了,只暴露必要的操作,隐藏底层实现细节。
#include <iostream>
#include <memory>
#include <vector>
// 手动实现 make_unique
#if __cplusplus < 201402L
namespace std {
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif
// 基类
class Shape {
public:
virtual double area() const = 0;
virtual std::string name() const = 0;
virtual std::unique_ptr<Shape> clone() const = 0;
virtual ~Shape() {}
};
// 派生类
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return 3.14 * radius * radius; }
std::string name() const override { return "Circle"; }
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Circle>(*this);
}
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override { return width * height; }
std::string name() const override { return "Rectangle"; }
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Rectangle>(*this);
}
};
// 句柄类
class ShapeHandle {
private:
std::unique_ptr<Shape> ptr;
public:
// 构造函数
template<typename T>
ShapeHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}
// 拷贝构造函数
ShapeHandle(const ShapeHandle& other) : ptr(other.ptr->clone()) {}
// 移动构造函数
ShapeHandle(ShapeHandle&& other) noexcept = default;
// 赋值运算符
ShapeHandle& operator=(ShapeHandle other) {
swap(*this, other);
return *this;
}
// 交换函数
friend void swap(ShapeHandle& a, ShapeHandle& b) noexcept {
using std::swap;
swap(a.ptr, b.ptr);
}
// 转发调用
double area() const { return ptr->area(); }
std::string name() const { return ptr->name(); }
};
// 使用示例
int main() {
// 创建句柄对象
ShapeHandle circle(Circle(5.0));
ShapeHandle rectangle(Rectangle(3.0, 4.0));
// 使用句柄对象
std::cout << circle.name() << " area: " << circle.area() << std::endl;
std::cout << rectangle.name() << " area: " << rectangle.area() << std::endl;
// 创建多态容器
std::vector<ShapeHandle> shapes;
shapes.push_back(circle);
shapes.push_back(rectangle);
// 遍历容器
for (const auto& shape : shapes) {
std::cout << shape.name() << " area: " << shape.area() << std::endl;
}
return 0;
}
#include <iostream>
#include <memory>
#include <string>
// 手动实现 make_unique (C++11 适用)
#if __cplusplus < 201402L
namespace std {
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif
// 文档接口
class Document {
public:
virtual void convertToPDF() = 0;
virtual void convertToWord() = 0;
virtual ~Document() {}
};
// Word文档
class WordDocument : public Document {
public:
void convertToPDF() override {
std::cout << "Converting Word document to PDF..." << std::endl;
}
void convertToWord() override {
std::cout << "Word document is already in Word format." << std::endl;
}
};
// PDF文档
class PDFDocument : public Document {
public:
void convertToPDF() override {
std::cout << "PDF document is already in PDF format." << std::endl;
}
void convertToWord() override {
std::cout << "Converting PDF document to Word..." << std::endl;
}
};
// 文档句柄类
class DocumentHandle {
private:
std::unique_ptr<Document> ptr;
public:
template<typename T>
DocumentHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}
void convertToPDF() { ptr->convertToPDF(); }
void convertToWord() { ptr->convertToWord(); }
};
// 使用示例
int main() {
DocumentHandle wordDoc{WordDocument()};
DocumentHandle pdfDoc{PDFDocument()};
wordDoc.convertToPDF();
wordDoc.convertToWord();
pdfDoc.convertToPDF();
pdfDoc.convertToWord();
return 0;
}
句柄类是 C++ 中一种强大的设计模式,它结合了继承和多态机制,提供了一种灵活且安全的方式来管理不同类型的对象。通过封装底层对象的实现细节,句柄类可以实现接口与实现的解耦,简化资源管理,并提供统一的操作接口。
在设计和实现句柄类时,需要注意以下几点:
通过合理运用句柄类,可以构建更加灵活、可维护的 C++ 程序,充分发挥面向对象编程的优势。