基本概念

首先定义如下的概念:

  • 接收元件:Receiver<Y,Ym>
  • 发送元件:Sender<Ym>
  • 接收者:拥有至少一个接受元(公开成员)的类
  • 发送者:拥有至少一个发送元件(公开成员)的类
  • 中转者:既是发送者也是接收者的类

其中:Ym是信息类型, Y是接收者类型,接收元件和发送元件必须使用同样的信息类型Ym, 才能建立联系进行信息传递。

信息会从建立连接的发送元件传递到接收元件,发送元件和接收元件之间可以是一对多或多对多地建议联系。

具体说明

元件之间的连接

发送元件和接收元件之间的连接是双向且对等的(与QT的信号和槽函数机制不同), 它们都可以与对方绑定与解绑(一对多,多对多)

1
2
3
4
5
6
7
sender.bind(receiver); // 发送元件可以绑定接收元件
sender.unbind(receiver); // 发送元件可以解绑接收元件
sender.unbind_all(); // 发送元件可以解绑所有的接收元件, 在析构时会自动调用

receiver.bind(sender); // 接收元件可以绑定发送元件
receiver.unbind(sender); // 接收元件可以解绑发送元件
receiver.unbind_all(); // 接收元件可以解绑所有的发送元件, 在析构时会自动调用

在发送元件内部会维持一个与自己连接的接收元件记录列表, 可以查询自己的状态

1
2
sender.num()             // 查询接收元件记录的个数
sender.is_bind(receiver) // 查询接收元件是否已被记录

对接收元件也是一样的

1
2
3
receiver.num()           // 查询发送元件记录的个数
receiver.is_bind(sender) // 查询发送元件是否已被记录
receiver.is_init() // 查询现在是否已经初始化

发送者的发送行为

  1. 创建信息message
  2. 在自己的方法内部主动调用发送元件的sender.exec(message)方法,将消息发送出去

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TestSender {
std::string m_name;

public:
MSender<int> int_sender_kernel;

explicit TestSender(const std::string &name): m_name(name) {
int_sender_kernel.name(nullptr);
}

// 调用发送元件来发送信息
void emit(int m) {
int_sender_kernel.exec(m);
}
};

接收者的接收行为

接收者在构造函数中需要调用init方法初始化接受元,将接收者的指针X和指定的公开方法指针Y传递给它。然后接收元件在收到消息后,就可以正确调用接收者的指定的公开方法,否则无效但不会报错,只是消息丢失了。

1
receiver.init(X,Y)

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TestReceiver {
std::string m_name;

public:
MReceiver<TestReceiver, int> int_receiver_kernel; // 接收元件

explicit TestReceiver(const std::string &name): m_name(name) {
// 把接收元件绑定到接收者自身和自身的方法
int_receiver_kernel.init(this, &TestReceiver::method);
}

void method(int m) {
// 接受元会自动调用这个方法
std::cout << " " << m_the_name << " receive " << m << " ("
<< int_receiver_kernel.num() << ")\n";
}
};

补充说明

为了让消息传递过程可视化,支持给发送元件和接收元件指定名称,

1
2
sender.name(name_str)
receiver.name(name_str)

如果设置了, 则在传递消息时会首先把名称字符串传递给std::cout,可以传入一个nullptr用来移除名称字符串。

不要使用detail_开头的接口, 这是不合适的操作, 但又不方便设置私有权限,可能导致指针和析构的错误。

源码

实现代码如下

signal.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#pragma once

#include <iostream>
#include <list>

// 基于std::list在发送元和接收元内部记录链表

// 把两个基类放置在m_signal子命名空间
// MSender和MReceiver放置在m_signal命名空间
// 使用bind和unbind两个方法进行绑定和解绑, 发送元和接收元都可以发起, 而且等价

namespace m_signal {

// 接收元基类的声明前置, 因为两个基类存在相互的调用关系

template <typename Ym>
class MReceiverBase;

// 发送元基类
// 需要使用接收元基类指针作为参数
template <typename Ym>
class MSenderBase {
public:
virtual ~MSenderBase() = default;

virtual void exec(Ym message) const = 0; // 发送行为

// 这两个也需要被接收元调用,因此首先在基类中定义

virtual bool
detail_sender_append(MReceiverBase<Ym> *receiver) = 0; // 保存接收元记录
virtual bool
detail_sender_remove(MReceiverBase<Ym> *receiver) = 0; // 删除接收元记录
};

// 接收元基类
// 需要使用发送元基类指针作为参数
template <typename Ym>
class MReceiverBase {
public:
virtual ~MReceiverBase() = default;

virtual void exec(Ym message) const = 0; // 接收行为

// 这两个也需要被发送元调用,因此首先在基类中定义

virtual bool
detail_receiver_append(MSenderBase<Ym> *) = 0; // 保存发送元记录
virtual bool
detail_receiver_remove(MSenderBase<Ym> *) = 0; // 删除发送元记录
};

} // namespace m_signal

// 前置声明
template <typename Ym>
class MSender;

// 接收元
// Y 接收者类型 Ym 信息类型
template <typename Y, typename Ym>
class MReceiver final : public m_signal::MReceiverBase<Ym> {
private:
Y *m_the_receiver = nullptr; // 接收者指针
void (Y::*m_the_func)(Ym) = nullptr; // 接收者将要调用的方法指针

std::list<m_signal::MSenderBase<Ym> *> m_the_senders; // 发送元记录

const char *m_the_name = nullptr; // 名称字符串

public:
// 默认构造函数
MReceiver() = default;

MReceiver(const MReceiver &) = delete;
MReceiver &operator=(const MReceiver &) = delete;

// 自带初始化的构造函数
MReceiver(Y *receiver, void (Y::*func)(Ym))
: m_the_receiver(receiver), m_the_func(func) {}

// 接收元的初始化
void init(Y *receiver, void (Y::*func)(Ym)) {
m_the_receiver = receiver;
m_the_func = func;
}

// 添加名称字符串, 会在exec的开头自动调用
void name(const char *name_str) { m_the_name = name_str; }

// 接收行为
// 被发送元的发送行为主动调用
void exec(Ym message) const {
if (m_the_name != nullptr) std::cout << m_the_name;

// 只有在初始化完成的情况下, 才会调用; 否则空指针不会调用
if (m_the_receiver && m_the_func) {
(m_the_receiver->*m_the_func)(message);
}
}

// 解绑全部, 析构会自动调用
// 通知所有记录的发送元调用sender_remove方法, 删除这个接收元记录
void detail_receiver_unbind_all() {
auto it = m_the_senders.begin();
while (it != m_the_senders.end()) {
(*it)->detail_sender_remove(this);
it = m_the_senders.erase(it);
}
}

// 接收元析构
~MReceiver() { detail_receiver_unbind_all(); }

// 保存发送元记录
bool detail_receiver_append(m_signal::MSenderBase<Ym> *sender) {
auto it = m_the_senders.begin();
while (it != m_the_senders.end()) {
if (*it == sender) { // 发送元已存在
return false;
}
++it;
}

m_the_senders.push_back(sender); // 保存发送元记录
return true;
}

// 删除发送元记录
bool detail_receiver_remove(m_signal::MSenderBase<Ym> *sender) {
auto it = m_the_senders.begin();
while (it != m_the_senders.end()) {
if (*it == sender) {
it = m_the_senders.erase(it); // 删除发送元记录
return true;
}
++it;
}
return false; // 发送元不存在
}

// 绑定发送元
void detail_receiver_bind(m_signal::MSenderBase<Ym> *sender) {
if (detail_receiver_append(sender)) {
sender->detail_sender_append(this); // 添加新的发送元时, 通知发送元
}
}

// 解绑发送元
void detail_receiver_unbind(m_signal::MSenderBase<Ym> *sender) {
if (detail_receiver_remove(sender)) {
sender->detail_sender_remove(
this); // 删除已有的发送元时, 通知发送元
}
}

// 更实用的接口

// 绑定, 转换指针为基类指针
void bind(MSender<Ym> *sender) {
detail_receiver_bind(static_cast<m_signal::MSenderBase<Ym> *>(sender));
}

// 解绑, 转换指针为基类指针
void unbind(MSender<Ym> *sender) {
detail_receiver_unbind(
static_cast<m_signal::MSenderBase<Ym> *>(sender));
}

// 解绑所有的发送元
void unbind_all() { detail_receiver_unbind_all(); }

// 查询发送元记录
bool is_bind(m_signal::MSenderBase<Ym> *sender) const {
auto it = m_the_senders.begin();
while (it != m_the_senders.end()) {
if (*it == sender) { // 发送元已存在
return true;
}
++it;
}

return false; // 发送元不存在
}

// 查询接收元记录的个数
size_t num() const { return m_the_senders.size(); }

// 查询接收元是否被正确地初始化
bool is_init() const {
return static_cast<bool>(m_the_receiver && m_the_func);
}
};

// 发送元
// Ym 信息类型
template <typename Ym>
class MSender final : public m_signal::MSenderBase<Ym> {
private:
std::list<m_signal::MReceiverBase<Ym> *> m_the_receivers; // 接收元记录

const char *m_the_name = nullptr; // 名称字符串

public:
// 默认构造函数
MSender() = default;

MSender(const MSender &) = delete;
MSender &operator=(const MSender &) = delete;

// 添加名称字符串, 会在exec的开头自动调用
void name(const char *name_str) { m_the_name = name_str; }

// 发送行为
// 遍历所有接收元记录, 依次触发接收元的接收行为, 传递信息
void exec(Ym message) const {
if (m_the_name != nullptr) std::cout << m_the_name;

auto it = m_the_receivers.begin();
while (it != m_the_receivers.end()) {
(*it)->exec(message);
++it;
}
}

// 解绑全部, 析构会自动调用
// 通知所有记录的的接收元调用receiver_remove方法, 删除这个发送元记录
void detail_sender_unbind_all() {
auto it = m_the_receivers.begin();
while (it != m_the_receivers.end()) {
(*it)->detail_receiver_remove(this);
it = m_the_receivers.erase(it);
}
}

// 发送元析构
~MSender() { detail_sender_unbind_all(); }

// 保存接收元记录
bool detail_sender_append(m_signal::MReceiverBase<Ym> *receiver) {
auto it = m_the_receivers.begin();
while (it != m_the_receivers.end()) {
if (*it == receiver) { // 接收元已存在
return false;
}
++it;
}

m_the_receivers.push_back(receiver); // 保存接收元记录
return true;
}

// 删除接收元记录
bool detail_sender_remove(m_signal::MReceiverBase<Ym> *receiver) {
auto it = m_the_receivers.begin();
while (it != m_the_receivers.end()) {
if (*it == receiver) {
it = m_the_receivers.erase(it); // 删除接收元记录
return true;
}
++it;
}
return false; // 接收元不存在
}

// 绑定接收元
void detail_sender_bind(m_signal::MReceiverBase<Ym> *receiver) {
if (detail_sender_append(receiver)) {
receiver->detail_receiver_append(
this); // 添加新的接收元时, 通知接收元
}
}

// 解绑接收元
void detail_sender_unbind(m_signal::MReceiverBase<Ym> *receiver) {
if (detail_sender_remove(receiver)) {
receiver->detail_receiver_remove(
this); // 删除已有的接收元时, 通知接收元
}
}

// 更实用的接口

// 绑定, 转换指针为基类指针
template <typename Y>
void bind(MReceiver<Y, Ym> *receiver) {
detail_sender_bind(
static_cast<m_signal::MReceiverBase<Ym> *>(receiver));
}

// 解绑, 转换指针为基类指针
template <typename Y>
void unbind(MReceiver<Y, Ym> *receiver) {
detail_sender_unbind(
static_cast<m_signal::MReceiverBase<Ym> *>(receiver));
}

// 解绑所有的接收元
void unbind_all() { detail_sender_unbind_all(); }

// 查询接收元记录
bool is_bind(m_signal::MReceiverBase<Ym> *receiver) const {
auto it = m_the_receivers.begin();
while (it != m_the_receivers.end()) {
if (*it == receiver) { // 接收元已存在
return true;
}
++it;
}

return false; // 接收元不存在
}

// 查询接收元记录的个数
size_t num() const { return m_the_receivers.size(); }
};

测试代码以及运行结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// main.cpp
#include <string>

#include "signal.hpp"

// 具体的接收者
class TestReceiver {
std::string m_the_name;

public:
MReceiver<TestReceiver, int> int_receiver_kernel; // 接收元
MSender<int> int_sender_kernel; // 发送元

explicit TestReceiver(const char *name) {
m_the_name = std::string(name);
// 把接收元绑定接收者自身和自身的方法
int_receiver_kernel.init(this, &TestReceiver::method);
}

// receiver_exec会调用这个方法
void method(int m) {
std::cout << " " << m_the_name << " receive " << m << " ("
<< int_receiver_kernel.num() << ")\n";

if (int_sender_kernel.num() > 0) { emit(m); }
}

void emit(int m) {
std::cout << m_the_name << " send " << m << ": ("
<< int_sender_kernel.num() << ")\n";

int_sender_kernel.exec(m);
}
};

// 具体的发送者
class TestSender {
std::string m_the_name;

public:
MSender<int> int_sender_kernel;

explicit TestSender(const char *name) {
m_the_name = std::string(name);
int_sender_kernel.name("TestSender int_sender_kernel\n");
int_sender_kernel.name(nullptr);
}

void emit(int m) {
std::cout << m_the_name << " send " << m << ": ("
<< int_sender_kernel.num() << ")\n";

int_sender_kernel.exec(m);
}
};

int main() {
TestSender Ada("Ada"); // 拥有一个发送元

TestReceiver Mike("Mike"); // 拥有一个发送元和一个接收元
TestReceiver John("John");
TestReceiver Jack("Jack");

Ada.int_sender_kernel.bind(&Mike.int_receiver_kernel); // Ada-> Mike
Ada.int_sender_kernel.bind(&John.int_receiver_kernel); // Ada-> John

Ada.emit(1);
// Ada发出信号
// -> Mike
// -> John

Ada.int_sender_kernel.bind(&Jack.int_receiver_kernel); // Ada-> Jack
Jack.int_sender_kernel.bind(&John.int_receiver_kernel); // Jack-> John

Ada.emit(2);
// Ada发出信号, 都会收到, 这时John会收到两次
// -> Mike
// -> John
// -> Jack
// Jack发出信号
// -> John

Ada.int_sender_kernel.unbind(
&Jack.int_receiver_kernel); // Ada不再绑定到Jack

Ada.emit(3);
// Ada发出信号
// -> Mike
// -> John

John.int_receiver_kernel.unbind_all(); // John的接收元解除了所有的绑定

Ada.emit(4);
// Ada发出信号
// -> Mike

return 0;
}