Reputation: 13
This is what I understand and I encourage you to correct me please: the visibility rules of inheritance of c++ classes are important if classes are inherited multiple times, correct?
class Base {
public :
int a;
protected :
int b;
private :
int c;
};
class Layer_1 : private Base { /* everything from ´Base´ is now */
int z{Base::a}; /* considered a private of ´Layer_1´ */
int r{Base::b}; /* but accessible here */
};
class Layer_2 : Layer_1 { /* Nothing in ´Layer_1´ is accessible from */
int y{Layer_1::a}; /* ´Layer_2´,as ´Layer_1´ inherited everything */
}; // invalid ~~~~^ /* from ´Base´ into their private scope */
protected
I can't go public
again, etc. Correct?Base
and Layer
class, it doesn't really matter how I inherit from Base
as I'm not inheriting from Layer
, correct?I hope this is no duplicate. I've looked but there was no question that answered this specific portion for me.
I got a bit confused and stumped when I couldn't really identify a pattern to how to use the different keywords.
Upvotes: 0
Views: 100
Reputation: 26949
The most important thing to know about access control in C++ is that it applies coequally and orthogonally to two different kinds of things:
For example:
class Dolphin : public Animal {
public:
int dorsal_fin_;
};
A Dolphin HAS-A dorsal fin, and a Dolphin IS-AN Animal; both of these facts are public
knowledge, available to anyone in the program. This means any random stranger in the program can write
Dolphin *d = ~~~;
use(d->dorsal_fin_);
Animal *a = d; // implicit conversion to pointer-to-base
and it'll Just Work. Also, that stranger can access d
as if it were an Animal (because it is publicly known to be an Animal) — he can use Animal's public API on d
. (Or even, I suppose, use Animal's private API, if Animal is friendly enough toward him.)
Contrary example:
class Dolphin : private Mammal {
private:
int vestigial_leg_;
};
A Dolphin HAS-A vestigial leg, and a Dolphin IS-A Mammal; but both of these facts are private knowledge, accessible only to class Dolphin
itself (and its members and its friends). That means that within Dolphin
I can write:
use(d->vestigial_leg_);
Mammal *m = d; // implicit conversion to pointer-to-base
but a random stranger could not write those lines, because from his point of view he doesn't know that a Dolphin
HAS-A vestigial leg and he doesn't know that a Dolphin
IS-A Mammal
. Those private relationships are inaccessible to him: he's not allowed to exploit them in the code he writes.
IMO everything else falls naturally out of the above, as logical consequences of these two rules.
Finally, there's protected
, which means "This relationship is accessible to me (and my members and my friends) and also to my child classes," except that it has some additional fiddly bits around the edges: basically the relationship is accessible to me but only if I'm operating on this
instead of on some random pointer I got from someone else. It's very fiddly and in my experience doesn't come up enough to bother with the exact details.
I strongly recommend that you use only a single level of inheritance. Use inheritance for classical polymorphism, in which you have an abstract base class to define the interface and a concrete derived class to define the implementation and then that's it. Don't use "implementation inheritance" if you can at all help it.
I fairly strongly recommend that you never use protected
; if you think you need to touch something in a child class, just promote it to public
. That is, factor your API carefully so that you can make each API member either 100% public
or 100% private
. This will complete the virtuous cycle: you'll never have to learn the subtleties of protected
because you'll never run into those subtleties because you'll never use it.
Upvotes: 1
Reputation: 7160
If I only have a Base and Layer class, it doesn't really matter how I inherit from Base as I'm not inheriting from Layer, correct?
No, that is incorrect.
Are there any known conventions or industry standards how and when to use public/protected/private or has this to be decided on each individual occasion and there's no 'rule'?
When you use inheritance for dynamic polymorphism, i.e., if you want "Derived is a Base" relationship, then you must have class Derived : public Base {/*...*/};
. This is the main purpose of inheritance, and this is the way it is used in other statically-typed languages (e.g., Java and C#).
If you want the inheritance to be an implementation detail, i.e., if nothing outside Derived
would care whether or not it is derived from Base
, then use class Derived : private Base {/*...*/};
. In most cases, "implemented in terms of" relationship should use containment rather than inheritance, so, instead of class Car : private Engine {/*...*/};
, you should use class Car { Engine engine; /*...*/};
, which makes the need for private inheritance rare.
Protected inheritance is, indeed, only important if you have more than one level in an inheritance hierarchy. The need for it is exceedingly rare. Do not use it until you get much more experience.
Upvotes: 0