Valid tive C ++ Clause 39: wise and prudent use of private inheritance

Source: Internet
Author: User

In C ++, public inheritance is considered as a-a relationship. Now let's look at private inheritance:

Class person {...};
Class student: private person {...};
Void eat (const person & P );
Void Study (const student & S );

Person P;
Student s;
Eat (P );
Eat (s); // error! Are students not people ?!

Obviously, private inheritance is not a-a relationship.

All members inherited from the private base class will become private attributes in the derived class, even if they are originally protected or public in the base class. Private inheritance means implemented-in-term-of (based on something ).

If Class D inherits Class B in the form of private, it is intended to use some of the features that have been prepared in Class B, not because the B object and D object have any conceptual relationship. Private inheritance is purely an implementation technique (that is why everything inherited from private base class is private in your class: because they are all implementation details ). In terms of Clause 34, private inheritance means that only the implementation part is inherited, and the interface part should be omitted. If D inherits B in the form of private, it means that D objects are implemented based on B objects. Private inheritance has no significance on the software "design" level, and its significance is only on the software implementation level.

Article 38 states that the significance of composition is also "is-implemented-in-term-of". How can we choose between them? Use compound as much as possible to use private inheritance only if necessary: when a person who wants to become a derived class wants to access a protected component intended to become a base class, or wants to redefine virtual functions, another radical situation is the strong spatial relationship.

A widget Class records the number of calls to each member function. Periodically review the information during runtime. To do this, we need to set a timer so that we can see if it is time to collect statistics.

To reuse existing code, we found Timer:

Class timer {
Public:
Explicit timer (INT tickfrequency );
Virtual void ontick () const;
};

Each tick calls a virtual function. We can redefine the virtual function so that the latter can retrieve the current status of the widget.

To allow widgets to redefine the virtual functions in timer, Widgets must inherit from timer. However, public inheritance is not appropriate because widgets are not a timer. You cannot call ontick for a widget. in concept, it is not part of the widet interface.

We must use private to inherit Timer:

Class Widget: Private timer {
PRIVATE:
Virtual void ontick () const;
};

Once again, putting ontick in the public interface will cause the customer to think they can call it, which violates Clause 18.

This design is good, but it is not worth a few RMB. Private multiplication is not absolutely necessary. If we decide to replace it with composite, we only need to declare a nested private class in the widget. The latter inherits timer in the form of public and redefines ontick, put an object of this type in the Widget:

Class widget {
PRIVATE:
Class widgettimer: Public timer {
Public:
Virtual void ontick () const;
};
Widgettimer timer;
};

This design is more complex than just using private inheritance, but there are two reasons you may be willing or should choose such public inheritance and combination:

First, you may want to design a widget so that it can have derived classes, but you may also want to prevent derived clssses from redefining ontick. If widgets inherit from timer, the above idea is impossible, and even private inheritance is impossible. (Article 35 states that derived class can redefine virtual functions, even if they cannot be called) If widgettimer is a private member within the widget and inherits timer, the derived classes of a widget cannot use widgettimer, so it cannot inherit it or redefine its virtual function. Some are similar to Java final or C # sealed.

Second, you may want to minimize the compilation dependency of the widget. If the widget inherits timer, the timer definition must be visible when the widget is compiled. Therefore, the file that defines the widget must contain timer. h. However, if the widgettimer removes the widget and the widget contains a pointer pointing to the widgettimer, the widget can only carry a simple widgettimer declarative expression and no longer need to include anything related to the timer. Such decoupling may be an important measure for large systems.

There is also a radical situation that only applies when the class you process does not contain any data. Such classes does not have a non-static member variable and does not have a virtual function (this function will bring a vptr to each object ), there is also no virtual base classes (such base classes will also incur additional overhead on the volume, see Clause 40 ). This so-called empty class object does not use any space because there is no data belonging to the object to be stored. However, for technical reasons, C ++ determines that all objects are independent (not affiliated) all objects must have a non-zero size:

Class empty {};
Class holdsanint {
PRIVATE:
Int X;
Empty E; // no memory is needed
};

You will find that sizeof (holdsanint)> sizeof (INT); an empty member variable actually requires memory. In most compilers, sizeof (empty) gets 1, because in the face of "a zero-size independent object", C ++ officially inserts a char to a null object. However, the homogeneous requirement (alignment) may cause the compiler to add some padding (padding) to classes like holdsanint, so it is possible that the holdsanint object has more than one char size, in fact, it is enlarged to one more Int.

The independent (non-affiliated) constraint does not apply to the base class components in the derived class object, because they are not independent. If you inherit empty, instead of containing an object of that type:

Class holdsanint: private empty {
PRIVATE:
Int X;
};

Almost certainly sizeof (holdsanint) = sizeof (INT ). This is the so-called EBO (empty base optimization: optimization of the blank base class). If you are a Library Development member and your customers are very concerned about space, it is worth noting that EBO. It is also worth noting that generally, EBO is only feasible under single inheritance (rather than multi-inheritance.

In reality, the "empty" class is not really empty. Although they have never had non-static member variables, they often contain typedefs, enums, static member variables, or non-virtual functions. STL has many technical purposes for empty classes, which contain useful members (usually typedefs), including base classes unary_function and binary_function, these are the classes inherited by "User-Defined Function objects. Thanks to the extensive practices of EBO, this inheritance rarely increases the size of derived classes.

Despite this, most classes are not empty, so EBO is rarely a legitimate reason for private inheritance. Both composite and private inheritance mean is-implemented-in-term-of, but composite is easier to understand. Therefore, you should choose composite whenever you can.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.