Sorry for the badly defined title. What I mean:
(Btw I am working on a game engine, and A is the Scene, B are the Game Objects and C are the Components)
I have 3 classes: A, B, C
A contains B, and B contains C.
A and B has a reference to each other.
B and C has a reference to each other.
(A is forward declarated in B's header, and included in B's implementation)
It's like this: A <-> B <-> C
My situation is this:
I want to use A's method from C. (Like telling the main container to add another B, etc)
~I want to make a reusable function which calls a method at the parent object's parent.
For example in C's derived classes I don't have to care how C reaches A, I just call C's Reach-A-and-do-something method.
My question is that which one should I use and why (or is there a better one?):
In C: GetB().GetA().DoSomething()
C's DoSomething() calls B's DoSomething() which calls A's DoSomething.
The first one looks nicer to me, but in C's implementation i only include B's header, where A is only forward declarated. So I can't use A's methods without explicitly including it in C. (Is this a bad practice, or should I just include it?)
The second one has a big overhead. If I want to use A's XY method, I have to create an XY method in B which calls A's XY and I have to create an XY method in C which calls B's XY.
So I don't know how should I reach higher elements in the hierarchy from the lower elements.
What is the best solution for this?
In C: GetB().GetA().DoSomething()
C's DoSomething() calls B's
DoSomething() which calls A's DoSomething.
I think both are wrong because from architectural standpoint such approach creates strong coupling between the classes. Consider using event dispatcher, that implements the Observer pattern for your logic. Let components send events to each other as well as react to them.
I am not sure about how will this work performance-wise in your case, but I strongly advise against premature optimization unless it's evident.
Related
I have three classes, A, B, and C. B and C are derived from A. Both B and C need to implement a method F. The code in B.F() is a subset of C.F().
Is it a good way declare A.F() as a virtual function and define B.F() and C.F()? There would be the same code in 2 methods, which I would like to avoid. What are the other
possibilities?
Define A.F() with the common code and override it in C.F(). While overriding how can the output of A.F() be used in C.F(), so that repeated code can be avoided?
I guess it's not the best thing to do. If you can avoid code rewriting - sure, do it.
It would be better to define F() in A, as you've said, with the common code for both B and C, and then override it in C.F(), using A::F() call in overriden function. I mean, with this you can firstly execute parent method A.F(), and then go with new extra logic. If you're inheriting B from A, you shouldn't then bother about this method in B at all.
Note that from this point of view, the order will be important. If you want parent code execution to be first, then call A::F() before your additional logic. It's on you to decide, what order to choose, though.
EDIT
I will add a link with a good example for you, if you don't know how to call parent method code inside child method. Take a look, and have a nice time.
I am currently working on a C++ design where I have this inheritance structure:
A
/ \
B C
Class A does the computations that are common to both classes B and C, and classes B and C are two different ways of initializing A.
I'd like to add some sort of hybrid initialization, i.e. a class D that would use methods from B and C.
However, I'd need to use diamond inheritance to be able to access B::init() and C::init() to set up the attributes of D.
I know I can avoid diamond problems using virtual inheritance, but I get runtime errors that I don't have when I copy manually the methods. Moreover, I have problems when trying to instantiate the classes B and C, and a colleague advised me to never use diamond inheritance in my designs.
Therefore, I'd like to find some kind of "clean" workaround, which I have not been able to do.
I could put all the initialization routines in class A, but for the moment they are separated nicely and I'd like to avoid having one big class where I can't really separate the distinct groups of functions of the classes B and C. EDIT after answer: This is what I chose, using different cpp files to split my "big" class into logical groups of methods.
I could also remove the inheritance links and replace them with friendship, where the methods of B and C are static and work on a pointer of type A*. This way, I could call B::init(A* a) and C::init(A* a) from D::init(A* a). However, I'd have to replace all the uses of _fooAttribute by a->_fooAttribute, which is a bit cumbersome and does not seem right.
What would you recommend ?
If your design calls for diamond inheritance, then that is what you need to do. People treat it as a "must not use" feature of C++, but the truth of the matter is that it is there, it is fully defined (if somewhat complex to understand), and if your problem space calls for it, you should use it.
In particular, I was not able to understand whether this is, indeed, a diamond inheritance. In particular, does it make sense for the A inside B and the A inside C to be the same instance of A? From your question it would appear that it is not. That Both B and C has a certain, different, way it makes sense to initialize A. If that is the case, this is not a diamond inheritance. Just make sure that B and C inherit A in a non-virtual inheritance.
With that said, make sure this is, indeed, what your design calls for. Can you honestly say that B is a A? That C? Can you honestly say that D is both a B and a C? If not, maybe making A a member of B, C or both, or making B or C members of D would make more sense.
If the only reason you are inheriting from A is as a way to extend A's provided methods, then consider simply making those methods a member of A. As stated above, while reducing code duplication is a worthy cause, the design should make sure that inheritance relationship is a is a relationship. Deviating from that is asking for trouble.
Inheritance is an "is a" relationship. If B is an A, then you're good. The same applies to C. From your description, you do not have this relationship. Instead, you have a utility class (A) that does computations. You might want to make this have static methods as it shouldn't need to store any data in itself, if it's truly a utility. There's nothing wrong with passing A an instance of B or C and having it access the properties that it needs using B->fooAttribute. However, you will probably want both B and C to implement a common interface so you don't have to know which one you're looking at.
Say I have an inherited class with function A and B. B does something and call A.
Base class also have function A and B. B does the thing in a different way and then call A (the derived class's A). However in a specific situation I want to call the base class's B. This is done using Base::B(). Then B will call A, my question is, which A will it call? The base one or the inherited one?
It depends whether A is virtual or not. If virtual the derived version will be called, if not it will be the base version.
You are proposing a generic scenario here, but it's enough to determine that you are referring to the MRO, aka Method Resolution Order, which is the algorithm ( or the class of algorithms, you can use this acronym to refer to a general topic or a specific single thing ) used to determine which method needs to be called.
How the MRO works in the C++ case it's described in the standard itself, but there is a dedicated tag here on SO named method-resolution-order and an answer that can give you a broad view about this.
I have diamond hierarchy of classes:
A
/ \
B C
\ /
D
To avoid two copies of A in D, we need to use virtual inheritance at B and C.
class A { };
class B: virtual public A {};
class C: virtual public A { };
class D: public B, public C { };
Question: Why does virtual inheritance needs to be performed at B and C, even though the ambiguity is at D? It would have been more intuitive if it is at D.
Why is this feature designed like this by standards committee?
What can we do if B and C classes are coming from 3rd party library ?
EDIT: My answer was to indicate B and C classes that they should not invoke A's constructor whenever its derived object gets created, as it will be invoked by D.
I'm not sure of the exact reason they chose to design virtual inheritance this way, but I believe the reason has to do with object layout.
Suppose that C++ was designed in a way where to resolve the diamond problem, you would virtually inherit B and C in D rather than virtually inheriting A in B and C. Now, what would the object layout for B and C be? Well, if no one ever tries to virtually inherit from them, then they'd each have their own copy of A and could use the standard, optimized layout where B and C each have an A at their base. However, if someone does virtually inherit from either B or C, then the object layout would have to be different because the two would have to share their copy of A.
The problem with this is that when the compiler first sees B and C, it can't know if anyone is going to be inheriting from them. Consequently, the compiler would have to fall back on the slower version of inheritance used in virtual inheritance rather than the more optimized version of inheritance that is turned on by default. This violates the C++ principle of "don't pay what you don't use for," (the zero-overhead principle) where you only pay for language features you explicitly use.
Why does virtual inheritance needs to be performed at B and C, even though the ambiguity is at D? It would have been more intuitive if it is at D.
In your example, B and C are using virtual specifically to ask the compiler to ensure there's only one copy of A involved. If they didn't do this, they're effectively saying "I need my own A base class, I'm not expecting to share it with any other derived object". This could be crucial.
Example of not wanting to share a virtual base class
If A was some kind of container, B was derived from it and stored some particular type of object - say "Bat", while C stores "Cat". If D expects to have B and C independently providing information on a population of Bats and Cats they'd be very surprised if a C operation did something to/with the Bats, or a B operation did something to/with the Cats.
Example of wanting to share a virtual base class
Say D needs to provide access to some functions or data members that are in A, say "A::x"... if A is inherited independently (non-virtually) by B and C, then the compiler can't resolve D::x to B::x or C::x without the programmer having to explicitly disambiguate it. This means D can't be used as an A despite having not one but two "is-a" relationships implied by the derivation chain (i.e. if B "is a" A, and D "is a" B, then the user may expect/need to use D as if D "is a" A).
Why is this feature designed like this by standards committee?
virtual inheritance exists because it's sometimes useful. It's specified by B and C, rather than D, because it's an intrusive concept in terms of the design of B and C, and also has implications for the encapsulation, memory layout, construction and destruction and function dispatch of B and C.
What can we do if B and C classes are coming from 3rd party library ?
If D needs to inherit from both and provide access to an A, but B and C weren't designed to use virtual inheritance and can't be changed, then D must take responsibility for forwarding any requests matching the A API to either B and/or C and/or optionally another A it directly inherits from (if it needs a visible "is A" relationship). That might be practical if the calling code knows it's dealing with a D (even if via templating), but operations on the object via pointers to the base classes will not know about the management D is attempting to perform, and the whole thing may be very tricky to get right. But it's a bit like saying "what if I need a vector and I've only got a list", "a saw and not a screwdriver"... well, make the most of it or get what you really need.
EDIT: My answer was to indicate B and C classes that they should not invoke A's constructor whenever its derived object gets created, as it will be invoked by D.
That's an important aspect of this, yes.
In addition to templatetypedef answer, it may be pointed out that you also may wrap A into
class AVirt:virtual public A{};
and inherit other classes from it. You wil not need to mark explicitly other inheriances as virtual in this case
Question: Why does virtual inheritance needs to be performed at B and C, even though the ambiguity is at D?
Because B's and C's methods must know they might have to work on objects whose layout is much different from B's and C's own layouts. With single inheritance it is not a problem, because derived classes just append their attributes after parent's original layout.
With multiple inheritance you cannot to that because there's no single parent's layout in the first place. Moreover (if you want to avoid A's duplication) parents' layouts need to overlap on A's attributes. Multiple inheritance in C++ hides quite a lot of complexity.
As A is the multiply-inherited class it is those that derive from it directly that have to do so virtual.
If you have a situation where B and C both derive from A and you want both in D and you can't use the diamond, then D can derive from just one of B and C, and have an instance of the other, through which it can forward functions.
workaround something like this:
class B : public A; // not your class, cannot change
class C : public A; // not your class, cannot change
class D : public B; // your class, implement the functions of B
class D2 : public C; // your class implement the functions of C
class D
{
D2 d2;
};
A class A possesses an instance c of a class C. Another class B has to modify c through C::setBlah(); method.
Is it bad to create an accessor C getC(); in A and then use A.getC().setBlah() ?
Or should I create a method A::setBlah(); that would call C::setBlah(); ? Isn't it annoying if there are several methods like that ?
As with most "is it bad to do X?" questions, the answer is that it depends entirely on a given situation.
Sometimes it might be a really bad idea to have a getC() sort of function because it breaks encapsulation. Other times it might be completely fine because encapsulation of that detail might be irrelevant, and writing a lot of wrapper functions increases the amount of code that you have to write.
Pick whichever makes the most sense for the given situation. In code that I've written, I've taken both approaches.
If you do go the getC() route, do make sure you return a reference; otherwise you'll be modifying a copy which doesn't sound like what you want. Or, you might consider making A::c public so that you don't need a function at all.
A third option to consider would be inheritance from C, which removes the need for getC() or wrapper functions in A.
A Method C getC(); creates a copy of c, so calling A.getC().setBlah() would modify the copy of c, not the c of A.
If C has many similar methods to be called by classes outside A, I would definitely not add these to A. I prefer to keep interfaces as minimal as possible. If these changes are related and are done together, you may add a dedicated single function to A to execute all calls to C at once and logically collect all these changes under an intuitive name.
Such a setup also raises the question: why does B need to touch A's member C? Maybe your design is not quite right - should C be a member of B rather than A?