Alternatives to static and global in C++?
Asked Answered
G

2

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.

Glover answered 27/4, 2015 at 7:43 Comment(7)
static in a class shares some disadvantages with global variables. The cleanest thing is the "cumbersome" parameter-passingSuperfuse
You should have a look about the Singleton Pattern : en.wikipedia.org/wiki/Singleton_patternPortiaportico
@Portiaportico ...except singletons are disliked because of the same reasons (after all, the usual singleton based on static class variables). Some reading: #138475 etc.etc.Superfuse
The Singleton pattern is just a glorified global variable. If you see that passing parameters in the constructor is cumbersome it might be time to flatten your dependencies somehow.Sissified
Hum... That's true. The question is more complex that I thought.Portiaportico
@BenjyKessler To pass the instance in the constructor would mean I have to pass it from the main (where mainWindow is instantiated) to the controller class and to all the GraphicsItems I use. This just did not feel right. I practically means every class in my program gets the instance in the constructor.Glover
(yes, a singleton can be useful. But people tend to extremely overuse it. In most cases I hear/see, I think it´s better without.)Superfuse
S
2

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.

Sweaty answered 27/4, 2015 at 10:26 Comment(0)
S
0

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.

Sissified answered 27/4, 2015 at 8:5 Comment(6)
So then a->b->c->d->doSomething(a); ? Whats the difference between this and always passing the pointer to the same istance? D d; C c(d); B b(d); A a(d);Glover
Who is calling doSomething? The class that calls it should hold a D and not an A.Sissified
Assuming A is the GraphicsItem to added to the QGraphicsScene D it would look like this: a->d->addItem(a); Or did I missunderstand your example?Glover
The idea is not to have a deep structure but rather have each class only know its own dependencies and not its subclasses dependencies. If a function of class a wants to call a function of class d then it should hold an instance of class d.Sissified
If you mean subclass, are speaking of inheritance? Because the controller class just instantiates the items there is no call to a super constructor.Glover
No I meant composition. Subclass==instances held by composition.Sissified

© 2022 - 2024 — McMap. All rights reserved.