当前位置: 首页 > news >正文

接上一篇,C++中,如何设计等价于Qt的信号与槽机制。

看下面例子:


class FileManager : public QObject {
    Q_OBJECT

public:
    FileManager(QObject* parent = nullptr) : QObject(parent) {}

    void changeFileName(const QString& newName) {
        fileName = newName;
        emit fileNameChanged(fileName);
    }

signals:
    void fileNameChanged(const QString& newName);

private:
    QString fileName;
};

所有连接类FileManage中的信号,在changeFileName函数中被调用。例如:

int main(int argc, char* argv[])
{
	QApplication a(argc, argv);  //注意,这里是QApplication
 
	FileManager fm;
	 

	QObject::connect(&fm, &FileManager::fileNameChanged, [](const QString& newName) {

		std::cout << "函数1收到:文件名改变了。\n";
	});


	QObject::connect(&fm, &FileManager::fileNameChanged, [](const QString& newName) {

		std::cout << "函数2收到:文件名改变2。\n";
	});


	fm.changeFileName("abc");

   
	return a.exec();
}

输出:

下面我们也来设计相同功能的FileManager2:

class FileManager2 {
public:
	using fileNameChanged = std::function<void(const QString& newName)>;

public:
	std::list< fileNameChanged> fileNameChanged_list;
public:
	FileManager2(QObject* parent = nullptr) {}

	void changeFileName(const QString& newName) {
		fileName = newName;
		for (fileNameChanged&  f: fileNameChanged_list) {
			if (f != 0)
				f(newName);
		}
	}
	 
	void connect(fileNameChanged f) {
		fileNameChanged_list.push_back(f);
	}
private:
	QString fileName;
};


int main(int argc, char* argv[])
{
	QApplication a(argc, argv);  //注意,这里是QApplication
 
	FileManager2 fm;
	 

	fm.connect([](const QString& newName) {

		std::cout << "函数1收到:文件名改变了。\n";
	});


	fm.connect([](const QString& newName) {

		std::cout << "函数2收到:文件名改变。\n";
	});


	fm.changeFileName("abc");

   
	return a.exec();
}

输出:

是不是一样,是不是很酷。:)

关键地方:

这里相当于Qt中的emit

这里添加一个函数指针,上篇说过:

这里可连接N个Lambda 表达式,与Qt一样:

连接函数:

最终也一样:

由于临时灵感来了,用了几分钟写的,难免有问题, 如果使用
std::list::remove 会编译不了,现在用新版方案替代,以后再完善:

template<class T>
class _callback {
public:

    friend bool  operator==(const _callback& l, const _callback& r) {
        return l.m_id == r.m_id;
    }

    _callback(const T& pf) {
        m_pf = pf;
        m_id = _DateTime::g_timeStamp();
    }

public:
    __int64 m_id;
    T m_pf;
};



class _FileManager {
public:
    using pf_fileNameChanged = std::function<void(const _string& oldPathName,
        const _string& newPathName)>;

      

    /// <summary>
    /// 更改文件名或路径并通知所有订阅者
    /// </summary>
    /// <param name="oldPathName"></param>
    /// <param name="newPathName"></param>
    /// 创建时间:2025-03-16    最后一次修改时间:2025-03-16
    void changeFileName(const _string& oldPathName, const _string& newPathName);


    /// <summary>
    /// 更改文件夹名或路径
    /// </summary>
    /// <param name="oldPathName"></param>
    /// <param name="newPathName"></param>
    /// 创建时间:2025-03-16    最后一次修改时间:2025-03-16
    void changeFolderName(const _string& oldPathName, const _string& newPathName);


    /// <summary>
    /// 删除文件
    /// </summary>
    /// <param name="fileName"></param>
    void deleteFile(const _string& fileName);


    /// <summary>
    /// 删除文件夹
    /// </summary>
    /// <param name="folderName"></param>
    void deleteFolder(const _string& folderName);


    // 订阅文件名更改事件
    void subscribe(const pf_fileNameChanged& callback) {
        std::lock_guard<std::mutex> lock(m_mutex); // 线程安全
        m_fileNameChanged.push_back(callback);
    }

    // 取消订阅文件名更改事件
    void unsubscribe(const pf_fileNameChanged& callback) {
        std::lock_guard<std::mutex> lock(m_mutex); // 线程安全
        m_fileNameChanged.remove(callback);
    }


private:
    _string m_dirPathName; // 当前文件名
    std::list<_callback<pf_fileNameChanged>> m_fileNameChanged; // 订阅者列表
    mutable std::mutex m_mutex; // 用于线程安全
};

相关文章:

  • TCP/IP四层网络模型
  • LeetCode hot 100 每日一题(10)——56. 合并区间
  • Chainlit 自定义元素开发指南:使用 JSX 和受限导入实现交互式界面
  • 软件工程:数据字典
  • 图解AUTOSAR_CP_WatchdogDriver
  • Python的类和对象(4)
  • Python函数默认参数为什么不能用可变对象
  • uniapp vue3项目定义全局变量,切换底部babar时根据条件刷新页面
  • Spring中Bean的自动装配
  • 电脑型号与尺寸
  • 大数据学习拓展——Minio安装与使用
  • Unity Shader - UI Sprite Shader之简单抠图效果
  • ollama docker设置模型常驻显存
  • 流量分析实践
  • 【Python 算法零基础 1.线性枚举】
  • 使用htool工具导出和导入Excel表
  • springboot学习(自定义starter)
  • GO语言的GC(垃圾回收)原理
  • 探索可变参数提升不变学习以增强分布外泛化能力
  • Android ARouter的详细使用指南
  • 网站如何做友情链接/全媒体运营师培训
  • 如何在电商网站做市场调研/企业网站seo贵不贵
  • 做振动盘的企业网站/第三方营销平台有哪些
  • 班组安全建设 网站/关键词指数批量查询
  • 做批手表批发发的网站/抖音seo怎么做
  • h5购物网站模板/世界搜索引擎大全