0

I am just starting out in large scale C++ software development. I am facing a design issue which I have no idea how to solve. The issue revolves around the following entities: an executable A and 3 libraries Q, W, E. Now, Library Q is on the lowest level meaning W, E, and A make calls into Q (independent/ standalone). In the current workflow, A makes calls into W; W makes calls into E and Q; and E makes calls into Q. The logical and physical dependencies are described below:

A -> W, Q;
W -> E, Q;
E -> Q

Everything was simple and straight forward and one directional until now. I started working on a feature in library 'E' for which I have identified a huge dependency on the executable 'A' itself. Dependency is in the form of processing which is currently done by 'A' and which is a lot.

E -> A

To solve the issue I am referring to Large-Scale C++ Software Design by John Lakos. However, I am unable to apply the techniques mentioned in there related to package circular dependencies (chapter 7) because what I am working with is 95% C code without any components and structure (5% C++). The amount of code which needs to be reorganized break to this dependency is way too much (over a few thousand lines spread across at least 4-5 source files).

One solution that comes to my mind is to create a base class in the library E and a derived class in application A. Use polymorphism to call the function in A from E. I am not sure if I can do this though because 'A' does not call directly into 'E' but through 'W'. However, A does link with E so it should be possible. Another one is to use function pointers to call into A ( which does not seem right).

Question: Is there a good known way to solve such a problem? And of the solutions I have mentioned above are there any hidden catches in implementing either of them? Which one is better? Any help is appreciated. Thanks in advance.

rustyBenz
  • 43
  • 5
  • Is [this](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes) what you're looking for? –  Nov 25 '19 at 06:25
  • I would strongly prevent to introduce a dependency of E from A (`E -> A`). Instead, E should provide slots which can be filled by A. One option: classes with virtual methods in E, which can be overloaded in A. Another option: E provides function pointers (e.g. `std::function`) where A can store call back functions. The latter is used in the popular [signal-slot concept](https://en.wikipedia.org/wiki/Signals_and_slots) - an implementation of [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern). In both cases, E can use features of A without "knowing" A. – Scheff's Cat Nov 25 '19 at 06:36
  • Having read the rest of your question, you already seem to be aware of these options. ;-) – Scheff's Cat Nov 25 '19 at 06:42
  • _Which one is better?_ This is hard to say. It depends on the concrete case. gtkmm provided always both options for event handling of widgets. I liked it very much. Whether to derive classes or just to install signal handlers for out-of-the-box class instances was always a choice. In opposition, Qt doesn't follow this concept in ful consequency. This is something I missed when I switched from gtkmm to Qt. – Scheff's Cat Nov 25 '19 at 06:46
  • Hi Scheff, thank you for your response!! At least I know I am on the right track. :) I am most likely going to go with the first option of creating a base class. This way I can keep all the dependencies consolidated under one entity. – rustyBenz Nov 25 '19 at 15:12
  • 1
    @Chipster I did take a look at that post however, the issue I have at hand is more to do with a logical dependency of a "library" on an "executable" which was not anticipated before. This dependency will result to calls in the form of "A->W->E->A" which could cause more issues going ahead. The other post talks about resolving circular dependency in builds / compile time errors which is not the case here. – rustyBenz Nov 25 '19 at 15:20

0 Answers0