You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 12:15:08