Qt5+C++:如何让子类自动锁定公共互斥量再执行重写方法?
问题描述
我有如下抽象类:
class Thing { public: Thing(); virtual ~Thing(); static QMutex s_mutex; virtual void load() = 0; virtual void translate() = 0; virtual void clear() = 0; };
并有多个Thing的子类实现。我希望这些子类的对应方法执行前必须锁定s_mutex,无需在每个子类中手动加锁(避免未来新增子类时遗忘)。
我想到了如下实现方式:
class Thing { public: Thing(); virtual ~Thing(); static QMutex s_mutex; void lockAndLoad() { QMutexLocker mutexLocker(&s_mutex); this->load(); } void lockAndTranslate(int amount) { QMutexLocker mutexLocker(&s_mutex); this->translate(amount); } void lockAndClear() { QMutexLocker mutexLocker(&s_mutex); this->clear(); } private: virtual void load() = 0; virtual void translate(int amount) = 0; virtual void clear() = 0; };
但这种方式繁琐且不够优化。我尝试过写一个接收函数参数的通用加锁执行函数,但因各方法签名不同无法实现;且即使实现,仍存在直接调用虚方法的风险。请问有没有更优的实现方案?
优化方案
方案一:可变参数模板实现通用加锁包装
借助C++11及以上的可变参数模板,实现通用的加锁执行逻辑,同时将虚方法私有化杜绝直接调用:
#include <QMutex> #include <QMutexLocker> #include <utility> // 用于std::forward class Thing { public: Thing() = default; virtual ~Thing() = default; static QMutex s_mutex; // 对外暴露的公共接口,自动加锁后调用私有虚方法 void load() { executeLocked(&Thing::loadImpl); } void translate(int amount) { executeLocked(&Thing::translateImpl, amount); } void clear() { executeLocked(&Thing::clearImpl); } private: // 所有业务逻辑虚方法设为私有,仅能通过公共接口触发 virtual void loadImpl() = 0; virtual void translateImpl(int amount) = 0; virtual void clearImpl() = 0; // 通用加锁执行模板,适配任意参数签名的成员函数 template<typename Func, typename... Args> void executeLocked(Func func, Args&&... args) { QMutexLocker locker(&s_mutex); // 完美转发参数并调用对应虚方法 (this->*func)(std::forward<Args>(args)...); } }; // 初始化静态互斥量 QMutex Thing::s_mutex;
该方案的核心优势:
- 仅需维护一个
executeLocked模板函数,新增业务方法时只需添加对应的公共接口,重复代码极少 - 虚方法完全私有化,彻底避免外部直接调用的风险
- 完美适配不同参数数量、类型的成员函数,扩展性极强
方案二:CRTP实现静态多态(无虚函数开销)
如果业务场景不需要运行时多态(即不需要用基类指针/引用统一管理子类对象),可以用CRTP(奇异递归模板模式)将加锁逻辑抽离到模板基类,消除虚函数的运行时开销:
#include <QMutex> #include <QMutexLocker> template<typename Derived> class ThingBase { public: static QMutex s_mutex; // 公共接口自动加锁后调用子类的实现方法 void load() { QMutexLocker locker(&s_mutex); static_cast<Derived*>(this)->loadImpl(); } void translate(int amount) { QMutexLocker locker(&s_mutex); static_cast<Derived*>(this)->translateImpl(amount); } void clear() { QMutexLocker locker(&s_mutex); static_cast<Derived*>(this)->clearImpl(); } }; // 初始化模板类的静态互斥量 template<typename Derived> QMutex ThingBase<Derived>::s_mutex; // 子类继承时传入自身类型,实现具体业务逻辑 class ConcreteThing : public ThingBase<ConcreteThing> { public: void loadImpl() { /* 你的load逻辑实现 */ } void translateImpl(int amount) { /* 你的translate逻辑实现 */ } void clearImpl() { /* 你的clear逻辑实现 */ } };
该方案的优势是避免了虚函数的运行时开销,但代价是失去了运行时多态的灵活性,适合不需要基类统一管理子类的场景。
内容的提问来源于stack exchange,提问作者Charles
相关产品推荐
相关产品推荐

