What is private inheritance? When I was studying at school, I had never studied such a thing carefully. Later, I used the boost library in my work to learn about it. If we say that most inheritance protection is for language integrity, private inheritance still has some usage.
Private inheritance vs public inheritance
Public inheritance inherits interfaces and implementations, which represent the relationship between classes.Is-. Private inheritance only inherits the implementation, which indicatesHas-
(Or Is-implemented-in-terms-.
In public inheritance, the public members of the base class are still public in the derived class, and the interfaces of the base class are completely passed to the derived class, that is to say, the base class object can be replaced with a derived class Object (Is-). Therefore, the compiler can safely convert the reference and pointer of the derived class object to the reference and pointer of the base class object. In private inheritance, the public and protected members of the base class become private in the derived class. from the outside world, the derived class Object no longer has the behavior of the base class. Therefore, the compiler does not perform similar conversions. Similarly, object slicing only appears in public inheritance.
Class base {public: void F () {cout <"base: f \ n" ;}}; class derived1: public base {}; class derived2: private base {}; void method (base & B) {B. F () ;}int main () {Base B; // base class object, OK method (B); derived1 D1; // a public derived class object, which is implicitly converted to a base class object, also OK method (D1); derived2 D2; // Private derived class object, cannot be converted to base class object, compilation error method (D2 );}
Nature of private inheritance
Private inheritance hides the interfaces of the base class, but these hidden functions can be called in the member functions of the derived class. Therefore, you can call the base class object function to complete some functions when implementing the derived class function (Is-implemented-in-terms-). In the following example, the penguin family inherits birds. There is no public inheritance because penguins are not strictly birds because they do not fly. If we want all penguins to skip the road, we can reuse the base class bird: Walk to complete the walk process.
Class bird {public: void fly (); void walk () ;}; class Penguin: Private bird {public: // walk () is implemented as a function, void jumpafterwalk () {walk (); jump ();} PRIVATE: void jump ();};
Private inheritance vs combination
In fact, private inheritance only implementsHas-Object combination (Composition/aggregation/containment) can achieve the same purpose. In the case of penguins, the bird object acts as a private member of the penguin family. The walking action of penguins is to call the Public member function (walk) of the private member (B). Penguins and bird objects are an inclusive relationship.
class Bird{public: void fly(); void walk();};class Penguin{public: void jumpAfterWalk() { b.walk(); jump(); }private: void jump(); Bird b;};
The same is true.Has-What are their advantages and disadvantages?
Advantages of Combination
(1) The combination is less coupling than the inheritance, especially when the penguin class holds the pointer of a bird object rather than the object. At this time, the header file containing the penguin definition does not even need to contain bird. h, but only one forward declaration is required. The advantage is that when the internal implementation of bird changes, the penguin class does not need to be re-compiled. This is very important in large projects.
// bird.hclass Bird{..};// penguin.hclass Bird;class Penguin{..private: Bird *b;};
(2) The Penguin class can have multiple bird Class Object members B1, B2 ..
Inheritance cannot do this.
Advantages of private inheritance
(1) You must inherit a class, but only want to keep some of the public interfaces. First, public inheritance is definitely not suitable because all the base class interfaces must be retained. You can use a combination, but since the combination does not expose the sub-object interfaces, You need to redefine the interfaces you want to retain. To implement the interface, you need to call the corresponding function of the sub-object. In comparison, private inheritance is much simpler. Because the base class interface Derived classes all have them, but they are private, you just need to declare them as public. In the following example, the derived classes only want to expose the F1 and F2 interfaces.
Class base {public: void F1 (); void F2 (); void F3 () ;}; // using private inheritance, exposing some interfaces becomes very simple class derived1: private base {public: using base: F1; using base: F2;}; // use a combination, slightly more complex class derived2 {public: void F1 () {B. f1 ();} void F2 () {B. f2 ();} PRIVATE: Base B ;};
(2) If you want to redefine a class virtual function, you have to use private inheritance. This does not seem so easy to understand: because it is private inheritance, how can we achieve Runtime polymorphism? After all, the pointer of a base class to a derived class object is not allowed. If it cannot be adjusted to a new virtual function defined by a derived class, what does it mean to implement it? The following example shows a possible model.
Class base {public: void F1 () {VF () ;}// equivalent to this-> VF (), the Runtime polymorphism protected: Virtual void VF () {cout <"base: VF () \ n" ;}}; class derived: Private base {public: void F2 () {F1 () ;}private: virtual void VF () {cout <"derived: VF () \ n" ;}}; int main () {derived D; D. f2 (); // print "derived: VF ()"}
(3) What should I do if I want to ensure that a class does not have copy attributes (such as mutex and database connection? One way is to privatize the copy constructors and value assignment operators. But there is still a problem that the member functions of the class can still call them. A better way is to inherit boost: noncopyable. Only when an object copy action exists will the compiler synthesize the copy constructor. At this time, the compilation error occurs because the copy function of the base class cannot be accessed. When there is no copy action, the copy function is not generated, and everything is normal. Note: Since the constructor of noncopyable is a protection attribute, the combination method is not feasible and can only be inherited. Although both private and public inheritance are technically feasible (because all noncopyable functions are no longer public), private inheritance is better, because here is exactly oneIs-implemented-in-terms-
Rather Is-.
Class noncopyable {protected: noncopyable (){}~ Noncopyable () {} PRIVATE: // emphasize the following members are private noncopyable (const noncopyable &); const noncopyable & operator = (const noncopyable &) ;}; class myclass: private boost: noncopyable {..} int main {myclass D1, D2; D1 = d2; // compilation error}
(4) Finally, when you need to use a class to protect members, you have to use private inheritance. This protects members from being invisible to the outside but visible to derived classes.
Thoughts on virtual destructor
When the private class inherits from a base class, the derived class object is no longer a base class object, and the compiler does not execute implicit type conversion, so there is no problem of releasing the derived class object through the base class pointer. Therefore, if you write a class that does not intend to be a base class, or you only want to be used as an implementation (private inheritance) of a later derived class, there is no need for a virtual destructor. The above boost: noncopyable is an example.
Summary:
- In private inheritance, all the members of the base class are private in the derived class. Therefore, the compiler does not perform implicit type conversion from the derived class to the base class.
- Public inheritance Representation Is-Private inheritanceHas-OrIs-implemented-in-terms-.
- Both private inheritance and combinationHas-Relationship. Generally, you can use combinations as much as possible, because they are loosely coupled and maintenance is simple and intuitive. It is used only when private inheritance is required.