接上一篇,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; // 用于线程安全
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值