c/c++如何进行模块化开发?
我只能处理最简单的情况,当只有 2 个模块 A 和 B
A 依赖于 B >,所以我将 B 构建为库,并将 B 的头文件包含在 A 中,同时链接到 B > 构建A时的库。
当A和B相互依赖时,这是行不通的,当模块数量增加时,情况更糟。
那么,进行模块化开发的一般方法是什么呢? c/c++
?
更新
抱歉,我的标题似乎不准确,重新表述的版本是:如何将一个模块分成许多 .h
和 .cpp
文件(没有一个)?
I can deal with only the easiest case, when there are only 2 modules A and B
A is dependant on B, so I build B as a library and include B's header file in A, also link to B library when building A.
This won't work when A and B are inter-dependant, and even worse when the number of modules grow ..
So what's the general way to carry out modularized development in c/c++
?
UPDATE
Sorry, seems my title is inacurate, the rephrased version is: how can I divide a module into many .h
and .cpp
files(not a single one)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果 A 和 B 相互依赖,则无法单独部署它们中的任何一个。因此,您实际上只有一个模块,而不是两个。 (不过,您可以重构模块以将通用内容提取到第三个模块 C 中,从而使 A 和 B 都依赖于 C,但不相互依赖。)
设计良好的项目不应包含循环模块依赖项。这保证了其模块之间始终存在合理的构建顺序。
更新
基本原则与模块级别非常相似:避免循环依赖和重复定义。 @Felix 已经提到了实现此目的的基本工具:前向声明和包含防护。我还可以赞同 @kotlinski 推荐的 Larman 书,以便更深入地了解该主题。
学习好的设计需要练习,所以如果您的第一种方法看起来不完美,请不要放弃:-) 在 C++ 中,一个特别的痛苦是更改后的过度重新编译。为了最大限度地减少这种情况,请努力确保您最依赖的事物(类、标头)是更改频率最低的事物。即依赖于接口(抽象类),而不是具体实现。
另外,努力保持逻辑分区(类/组件)和物理分区(头文件/cpp 文件)之间的健康关系。典型的方法是将每个类定义放入单独的头文件中,并将其实现(如果适用)放入单独的 cpp 文件中。但是,您可能更喜欢在单个标头中定义紧密耦合的类(组件),以强调它们的逻辑关系。
If A and B are inter-dependant, you can't deploy any of them in isolation. Therefore you practically have a single module, not two. (You can refactor your modules to extract the common stuff into a third module C though, thus making both A and B depend on C but not on each other.)
A well designed project shall not contain cyclical module dependencies. This guarantees that there is always a sane build order between its modules.
Update
The basic principle is pretty similar to that of the module level: avoid cyclic dependencies and duplicate definitions. @Felix already mentioned the essential tools for this: forward declarations and include guards. I can also second @kotlinski's recommendation of the Larman book for a deeper understanding of the topic.
Learning good design takes practice, so don't give up if your first approach doesn't look perfect :-) In C++, one particular pain is excessive recompilation after changes. To minimize this, strive to ensure that the things (classes, headers) you depend on the most are the ones which change the least frequently. I.e. depend on interfaces (abstract classes), not concrete implementations.
Also, strive to keep a healthy relationship between the logical partitioning (classes/components) and the physical partitioning (header/cpp files). The typical way is to put every class definition into a separate header file, and its implementation (if applicable) to a separate cpp file. However, you may prefer defining tightly coupled classes (components) in a single header, to emphasize their logical relationship.
一般来说,拥有两个相互依赖的模块是一种设计味道。您可以
1) 将模块合并到新的 C 中,或者
2) 将公共子集提取到 I 中,使 A 和 B 依赖于 I 但彼此不依赖。
更新
使用前向声明和#pragma Once或#include/#ifndef保护:
什么时候可以使用前向声明?
我应该在标头中使用#include ?
Generally speaking, having two interdependent modules is a design smell. You can either
1) merge the modules into a new one C, or
2) extract a common subset into I, making A and B depend on I but not each other.
update
Use forward declarations and #pragma once or #include/#ifndef protection:
When can I use a forward declaration?
Should I use #include in headers?
解决方案是确保您的模块形成有向无环图...即,如果 A 依赖于 B,请确保 B 不依赖于 A。这需要大量的纪律,但从长远来看是值得的。
如果您对这些东西感兴趣,大规模 C++ 软件设计 是一个不错的选择读。
The solution is to make sure your modules form a directed acyclic graph... I.e. if A depends on B, make sure B doesn't depend on A. It takes a lot of discipline but is worth it in the long run.
If you are interested in this stuff, Large Scale C++ Software Design is a good read.
设计模式,例如模型–视图–控制器 - MVC。
模型-视图-控制器 (MVC) 是一种软件架构,1 目前考虑软件工程中使用的一种架构模式。该模式将“域逻辑”(用户的应用程序逻辑)与输入和表示(UI)隔离,允许各自独立开发、测试和维护。
Design Patterns, for example Model–View–Controller - MVC.
Model–View–Controller (MVC) is a software architecture,1 currently considered an architectural pattern used in software engineering. The pattern isolates "domain logic" (the application logic for the user) from input and presentation (UI), permitting independent development, testing and maintenance of each.