1_C++进程内模块之间调用函数的方式

       对于程序猿来讲,这个问题很熟悉,编程的话一定会涉及到。尤其在使用开源库时,一般会选择链接库文件,include头文件,也有一些开源库可能直接使用hpp文件,头文件和实现都在一个文件。依稀记得几年前问了徐先生一句,我的一个函数如何获取另一个函数的某个参数,他说方法有好几种,不过后面我也没具体在网上搜索查询,今天算是做一个小结吧。

一、范围划定

进程内不同类(模块)之间函数访问的方式有几种,有什么优缺点?

在进程内,不同模块/类之间调用函数,常见的方式大致可以分为以下几类。下面列出 6 种典型方案,并对它们的优缺点做简要比较:

1、编译时静态链接(直接调用)

做法

两个模块在编译/打包期就确定依赖关系,源文件里 #include(C/C++)或 import(Java/Python)对方的头文件/模块,然后直接调用对方的类方法。

优点

运行效率高(编译器能做内联、优化)。

代码路径清晰、可读性好。

IDE/编译器能进行完整的类型检查与重构支持。

缺点

耦合度高,改动一方常需要重新编译、回归测试。

难以做到运行时替换或插件式扩展。

2、回调/函数指针/委托(Callback / Delegate)

做法

将目标函数指针、函数对象/Lambda、接口实例等以参数形式传入被调用方,运行时再“回调”执行。

优点

典型的“依赖倒置”,可减少模块间直接依赖。

支持运行时灵活替换具体实现。

缺点

代码可读性略差,调用链不如直接调用直观。

调试时要追踪回调栈,比直调更麻烦。

若函数签名不统一,接口设计成本增高。

3、观察者/发布-订阅(Observer / Pub‑Sub / Event Bus)

做法

定义一个事件总线(EventBus),模块 A 发布(publish)某类事件,模块 B 订阅(subscribe)并在收到通知时执行回调。

优点

极低耦合:发布者和订阅者互不依赖。

易于广播式通知,多对多场景非常合适。

缺点

隐式调用链,不容易从代码上看出事件流向。

难以保证处理顺序,调试、错误定位成本高。

性能略差,事件分发有额外开销。

4、服务定位器/单例模式(Service Locator / Singleton)

做法

将若干公共服务或工具类做成全局单例,其他模块通过 ServiceLocator.get(…) 或者 Singleton.getInstance() 获取并调用。

优点

使用方便,任何地方都能拿到实例。

对已有代码改动最小,快速引入。

缺点

隐藏依赖关系,模块之间的依赖不显式,维护困难。

单例全局状态易导致测试困难、潜在并发问题。

5、反射/动态调用(Reflection / Dynamic Invocation)

做法

通过语言运行时的反射 API(如 Java 的 Class.forName、Python 的 getattr)或动态代理,根据字符串/元数据决定调用哪个方法。

优点

极度灵活,可在运行时根据配置或元数据决定行为。

适合框架层面通用功能(比如 RPC 框架、序列化库)。

缺点

性能相对较差,有额外的运行时开销。

编译期难以检查,容易在运行时才暴露调用错误。

可读性、可维护性下降。

6、动态加载插件(Plugin/Module Loader)

做法

使用操作系统的动态链接库(如 dlopen/LoadLibrary),或语言级别的动态导入(如 Python 的 importlib),运行时加载外部模块,并通过预定义接口调用。

优点

支持热插拔式扩展,方便做插件化架构。

主程序与插件仅通过接口契约耦合,升级、部署更灵活。

缺点

实现复杂度高,需要处理版本兼容、生命周期管理。

调试/打包/部署流程更繁琐。

选择哪种方案,需根据项目规模、性能要求、可维护性以及模块间耦合度等因素综合权衡。

二、几个其他问题

1、rpc问题

如果未来程序朝着跨进程跨硬件演变,设计接口时如何考虑进程内与跨进程兼容?

欢迎关注:

一个希望50岁退休的打工人~

共同交流进步,体会工业化进程~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值