Valid tive C ++, 3rd edition, item 34: distinguish between inheritance of Interface (interface inheritance) and Inheritance of implemen

Source: Internet
Author: User

Item 34: differentiate inheritance of Interface (interface inheritance) and inheritance of implementation (implement inheritance)

By Scott Meyers

Translator: fatalerror99 (itepub's nirvana)


(Public) inheritance is a simple and easy-to-understand concept. Once it is closely examined, it will prove that it is composed of two independent parts: inheritance of function interfaces (Inheritance of function interfaces) and Inheritance of function implementations (Inheritance of function implementation ). The differences between the two inheritance exactly match the differences between function declarations (function declaration) and function definitions (Function Definition) discussed in introduction.

As a class designer, sometimes you want Derived classes to inherit only the interface (Declaration) of a member function ). Sometimes you want Derived classes to inherit both interfaces and implementation, but you need to allow them to replace the implementation they inherit. In other cases, you want Derived classes to inherit the interface and implementation (implementation) of a function, without allowing them to replace anything.

To better understand the differences between these options, consider a class hierarchy that represents ry in a graphics application (class inheritance system ):

Class shape {
Virtual void draw () const = 0;

Virtual void error (const STD: string & MSG );

Int objectid () const;


Class rectangle: Public shape {...};

Class ellipse: Public shape {...};

Shape is an abstract class. Its pure virtual function (pure virtual function) indicates this. As a result, the customer cannot create an instance of shape class, but can only create an instance of classes inherited from it. However, shape has a very strong impact on all classes inherited from it (public), because

  • Member FunctionsInterfaces are always inherited. As explained in item 32, public inheritance means is-a, so anything that is true for a base class must also be true for its derived classes. Therefore, if a function applies to a class, it must also apply to its derived classes.

The shape class declares three functions. First, draw the current object on a clear display device. Second, error. When an error needs to be reported (the original text here is incorrect, which is modified based on the author's website Errata-Translator's note), it is called. Third, objectid, returns the unique integer identifier of the current object. Each function is declared in a different way: draw is a pure virtual function (pure virtual function); error is a simple (impure ?) Virtual function (simple virtual function), while objectid is a non-virtual function (non-virtual function ). What do these different statements imply?

Consider the first pure virtual function (pure virtual function) draw:

Class shape {
Virtual void draw () const = 0;

Two of the most notable features of pure virtual functions (pure virtual functions) are that they must be re-declared by any specific class that inherits them, and they are generally not defined in abstract classes. Add these two features together and you should realize that

  • The purpose of declaring a pure virtual function (pure virtual function) is to make Derived classes inherit a function.Interface only.

This makes the shape: Draw function have a complete meaning, because it requires that all shape objects be properly drawn, however, the shape class itself cannot provide a reasonable default implementation for this function. For example, the algorithm for drawing an ellipse is very different from the algorithm for drawing a rectangle. The shape: Draw statement tells the designer of the derived classes: "You must provide a draw function, but I have no comments on how you implement it."

By the way, it is possible to provide a definition for a pure virtual function. That is to say, you can provide an implementation for shape: draw, and C ++ will not complain about anything, but the only way to call it is to use the class name to limit this call:

Shape * PS = new shape; // error! Shape is abstract

Shape * PS1 = new rectangle; // fine
PS1-> draw (); // CILS rectangle: Draw

Shape * PS2 = new ellipse; // fine
PS2-> draw (); // callellipse: Draw

PS1->Shape: Draw (); // Callshape: Draw

PS2->Shape: Draw (); // Callshape: Draw

In addition to helping you impress fellow programmers at cocktail parties, this feature is usually useless. However, as you will see below, it can be used as a mechanism to "provide a safer-than-usual implementation for simple (impure) virtual functions.

The story behind simple virtual functions is a little different from that of pure functions. Derived classes still inherits the interface of the function as usual, but simple virtual functions provides an implementation that can be replaced by Derived classes. If you think about it for a while, you will realize

  • The purpose of declaring a simple virtual function is to let Derived classes inherit a function.Interface as well as a default implementation.

Consider the case of shape: Error:

Class shape {
Virtual void error (const STD: string & MSG);

The interface requires that each class must support a function called when an error occurs, but each class can use any method that it feels appropriate to handle the error. If a class does not need to do anything special, it can turn to the default version of error handling provided in the shape class. That is to say, the shape: Error statement tells the designer of derived classes: "You should support an error function, but if you do not want to write it yourself, you can ask for the default version in shape class ."

The result is: it is dangerous to allow simple virtual functions to specify both a function interface and a default implementation. Let's take a look at the reason for considering the hierarchy (inheritance system) of an XYZ Airline plane ). XYZ has only two types of aircraft, model A and model B. Both of them fly exactly in the same way. Therefore, XYZ is designed as follows hierarchy (inheritance system ):

Class airport {...}; // represents airports

Class airplane {
Virtual void fly (const airport & Destination );



Void airplane: Fly (const airport & Destination)
Default Code for flying an airplane to the given destination

Class modela: Public airplane {...};

Class modelb: Public airplane {...};

Airplane :: fly is declared as virtual. However, to avoid repeated code in modela and modelb classes, the default flight behavior is provided by the airplane: Fly function body for modela and modelb to inherit.

This is a classic object-oriented design. Because two classes share a common feature (which implements the fly method), this general feature is transferred to a base class and inherited by two classes. This design makes general features clear, avoids code duplication, improves future scalability, and simplifies long-term maintenance-because of the object-oriented technology, all these things are highly sought after. XYZ airlines should be proud of it.

(Click here, next)

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: 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.