65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 的动态消息传递

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2009 年 3 月 23 日

CPOL

2分钟阅读

viewsIcon

56205

downloadIcon

415

C++ 的动态消息传递。

引言

像 Smalltalk 和 Objective-C 这样的编程语言被认为比 C++ 更灵活,因为它们支持动态消息传递。C++ 不支持动态消息传递;它只支持静态消息传递:当调用对象的某个方法时,目标对象必须具有被调用的方法;否则,编译器会输出错误。

虽然 C++ 的消息传递方式比 Smalltalk 或 Objective-C 的方式快得多,但有时需要 Smalltalk 或 Objective-C 的灵活性。 这篇文章展示了如何在 C++ 中以最少的代码实现动态消息传递。

背景

C++ 通过 虚表 (vtables) 来实现消息传递。

Smalltalk 和 Objective C 使用方法映射 (method map) 来实现相同的结果。

示例

提供的头文件包含动态消息传递的实现。为了向对象添加动态消息传递能力,必须执行以下操作:

  1. 声明一个全局函数,作为消息的签名。
  2. dmp::object 继承。
  3. 在类构造函数中,使用 add_message 方法向对象添加一个或多个消息。
  4. 使用函数 invoke(signature, ...parameters) 向对象发送消息。

这是一个例子。

//the dynamic-message-passing header
#include "dmp.hpp" 

//the message signature
std::string my_message(int a, double b) { return ""; }

//a class that accepts messages dynamically
class test : public dmp::object {
public:
    test() {
        add_message(&::my_message, &test::my_message);
    }

    std::string my_message(int a, double b);
}; 

int main() {
    test t;
    std::string s = t.invoke(&::my_message, 10, 3.14);
}

工作原理

每个对象包含指向映射的共享指针。映射的键是指向消息签名的指针。映射的值是指向内部消息结构的指针,该结构保存着要调用的方法的指针。

当调用一个方法时,从映射中检索适当的消息结构,并使用 this 作为目标对象,调用消息结构中存储的对象的该方法。

出于效率的原因,内部使用的映射是无序的。

为了提高效率,对象的消息映射也在对象之间共享。当修改消息映射时,如果它不是唯一的,则会对其进行复制,即应用写时复制模式。

只有当不同线程在查找消息映射时,消息映射没有被修改,代码才是线程安全的。如果修改了消息映射,则任何线程都不应同时向对象发送消息。

代码使用 boost 库是因为:

  1. 无序映射;使用了类 boost::unordered_map
  2. 预处理器;用于自动为不同数量的参数构建代码。
  3. 共享指针;用于内部内存管理。
© . All rights reserved.