Alternatives to static and global in C++?

2019-06-15 21:11发布

问题:

I have a class instance that needs to be accessed by some other classes.

  • It would be quite cumbersome to pass the instance always down the construction chain.
  • I tried to avoid global variable, since people tend to advise against this.
  • I thought I declare this instance a static member of a class and then include this class in order to access the instance but this does not work either

error: calling a private constructor of class 'Foo'

To specify the problem further in the context of the QGraphicsView Framework: I want to add QGraphicsItems which are instantiated by a controller class (managing the items) to the QGraphicsScene, which is (but I do not insist on that detail) a member of my QMainWindow class.

I spend a considerable amount of time searching the internet but I am fairly new and am kind of stuck here. I appreciate any incentive on what the best way to solve the dilemma would be.

回答1:

The use of globals are extremely controversy discussed, that's why I want to point out, that what I write in the following is my personal opinion and open to discussion.

I know no way beside passing instance to resolve your problem without a global object. I personal do not think that a global instance is an evil thing in all situation.

  1. When I design a library I tend to avoid global objects except one factory. Global objects are often used as shortcut where no shortcut is needed or to avoid some typing for the programmer. Also, mostly classes in a library should be independent. You sacrifice independency if you use global instances inside such classes.

  2. When I use statics in a class, I only use them if the whole class is a singleton or for factory methods (e.g. create or get). Never in a way you described. In the way you described it, it is unexpected for other developer, because you need a third party to initialize that static object. You gain nothing with that except avoid typing a longer constructor. This cannot be a goal.

  3. If I use a global instance, I always wrap it in a management class. I never use third party classes like QGraphicsItems direct as globals (also no "primitive" classes or types). Like in point 2, other may not expect that as global. More important it is not clear who has to fill or kill the instance. A "GraphicsItemManager" can have a "setup" method which makes that totally clear to 3rd users.

  4. Passing instances is not in every situation the best way IMHO. Not all my classes are for reuse, they are solely for one project. Here the speed of realization, the ease of use and the clear grouping worth more than a dogma as "no globals". Most time I write manager classes which group instances of e.g. graphic items. I do not have the feeling that makes the code less readable as long I used the rules I pointed out before.

  5. Sometimes a resource is not available by construction time, so you have already pass a wrapper. This leads to a point where you have pass instances through classes which themselves do not need that resource or are themself part of a library (in that case, often you cannot change the constructor). This can (as we are all humans) lead to misinterpretation. I use global management classes to jump over those "gabs", as I think it worth more to keep that space clean from dependencies.

As I wrote IMHO.



回答2:

This problem arises when you have a design where class A creates class B which creates class C which needs to accept an instance of class D in its constructor. Then you have to pass D all the way through A, B and C. If you change the design to have a create instances function (either in the main or in some factory class) which knows how to create A, B, C and D. Then you can write this function as follows:

D d;
C c(d);
B b(c);
A a(b);

This way each class only accepts its dependencies.

If you later realize that B also needs to use class D then you can just change the constructor of B without affecting the constructor of A.