What is inheritance in C.

"I'm afraid this is a hereditary disease." Then please send your bill to my father. "

Computer science is full of beautiful analogies. Object-oriented programming, for example, introduced the term "inheritance" when a class is derived from another class and inherits its properties. The term heredity here has less to do with the will of a deceased relative than with the biological rules that a Mr. Mendel thankfully discovered. Since my knowledge of biology is rather regrettable, you will have to forego an entertaining excursion into biology here. But once you get your hands on a biology book, you'll find that Mendelian rules don't behave the same way as base classes and their derived classes anyway. Still, I know at least one biologist who has become a great programmer.

Base class

A class can serve as the basis for developing a new class without having to change its code. To do this, the new class is defined and it is stated that it is a derived class of the base class. All public elements of the base class then also belong to the new class without having to be declared again. The new class is said to inherit the properties of the base class.

Reusing the code

Since the base class does not have to be changed and the code is incorporated into the derived class without further adaptation, this form of code reuse is largely risk-free.

specialization

The elements that are defined in the derived class make the derived class a special case of the base class. It has all the properties of the base class. You can add new items. The following example shows why adding properties is a specialization.

example

From the point of view of a computer program, all persons have names, addresses and telephone numbers. Business partners also have bank details. Since the business partners are also people, they have names, addresses and telephone numbers in addition to their bank details. Some business partners can be customers. In addition to the properties of a business partner, customers also have a delivery address. Suppliers are not customers, but they are also business partners. You still have outstanding invoices. Even employees are actually business partners because they have bank details. They also have health insurance. Field workers have all the characteristics of an employee and also their district.

At this point in the book there is the figure "Person Classes" (abbpersonenerbe)

This represents the starting class person generalization and each derived class a specialization. The advantage of this technique is that the existing code of the base class does not have to be rewritten for the newly created class. For example, a check function of the address would be that of the class person is automatically added to all other classes, directly or indirectly, from person derived without writing a line of code. A change in class Employee would always have an impact on the sales force. But there is no retroactive effect on the business partner.

"Is a"

In this case one speaks of an "is a" relationship. The customer "is" a business partner. It has all the characteristics of a business partner and only adds its special features, here the delivery address. In addition to the data elements, the functions, such as the address check mentioned above, are also inherited. Only the constructors, the destructors and the assignment operators are not inherited.

Example company

The class from which a class inherits is expressed in C ++ by putting a colon after the keyword and the class name in the class definition. Then the keyword and the name of the base class are given. In order not to develop the common properties for every group of people, a basic class is first developed person. Each of the groups of people can from person and inherits all of a person's characteristics. What the classes have in common is found in person implemented. The health insurance is only implemented for employees. In contrast, the delivery address is only implemented for the customer. If you also want to manage suppliers, you can click on the type person can be used. The supplier also inherits everything from the person and has a few more properties, such as a list of open invoices.

[People]

class Person {public: string name, address, phone; }; class partner: public person {public: string account, bank code; }; class employee: public partner {public: string health insurance; }; class customer: public partner {public: string delivery address; }; class supplier: public partner {public: open items * invoices; }; class field service: public employee {public: tBezirk Bezirk; };

Compatibility with the base class

Since publicly derived classes contain the complete interface of their base class, they are assignment-compatible to the base class. An object of type Employee can therefore be an object of type person be assigned to. After the assignment, however, the information about the health insurance company and the bank details are lost. The copied object no longer has the extensions of the derived class. The address of the object of a derived class can be assigned to a pointer to the base class. In this case, the object does not lose any information because it is not changed. It doesn't work the other way around. The object of a base class cannot be assigned to an object of a derived class. Person person; Employees employees; person = employee; // ok employee = person; // the compiler doesn't like that

Example tDate

If you have a class tdate have written that should be used for a calendar, then you also need holidays. From the perspective of a calendar, these differ in that each holiday has a name. You could of course add a name to each date. Most days are not public holidays. The idea of ​​a class is better t holiday of tdate and just add the name to it.

[Holiday]

class tHolidays: public tDate {public: char name [40]; }; t Easter holiday; Easter.day = 25; Easter.month = 4;

You can then use the object Easter deal with any instance of tdate. The class t holiday inherits all properties of tdate and just adds the peculiarities of a holiday. A major benefit is that you have the class tdate do not have to change. Any change to a code segment can lead to errors. For this reason, it is also possible that in larger projects you will not be given any authorization at all to change classes from which you want to derive something. Precisely because the user of the base classes does not have to adapt the code in the base class, class libraries are more flexible than function libraries. Changes are simply made in a derived class.

Access to the ancestors

By default, elements of a class are only accessible to other elements of this class. Elements that should also be accessible from other classes are declared as. This also applies to inheritance. A derived class cannot access the private members of the base class. In contrast, it can access the public elements of the base class as it does its own. Due to inheritance, there is an additional access variant in addition to and. The attribute is called and has the effect that only derived classes get access to the elements. In the following section we will look at what it actually means that an inheritance is carried out publicly.

protected

In addition to access rights and inheritance, there is a third variant. It can be used to privatize class elements in such a way that, apart from their own class, they can only be accessed by the derived class. The keyword is used for this.

[protected]

class base {private: int private; protected: int protect; public: int public; }; class Derived: public base {void access () {a = private; // That'll cause trouble! a = protect; // That's working. a = public; // That works anyway. }}; int main () {base myVar; a = myVar.private; // Of course that doesn't work. a = myVar.protect; // That also does not work. a = myVar.publik; // That's working. }

Changing the public

A derived class can put the elements of the base class accessible to it in a different public. Example:

[Change the access type]

class base {private: int private; protected: int protect; public: int public; }; class Derived from: public base {protected: using base :: public; public: using Basis :: protect; }; int main () {Derived from a; b = a.protect; // O miracle, it works! }

You will rarely find such a procedure in practice because it gives the impression that the design was not worked carefully. It is therefore only to be regarded as a stopgap solution in order to correct inappropriately assigned access rights by deriving them.

Access attributes for inheritance

So far we have only looked at derivatives that place the keyword in front of the name of the base class. It is obvious that there can also be or instead of. You should be aware of the consequences because omitting the inheritance attribute always means that the class is derived privately. Public members of the base class become private by deriving private in the derived class.

[Private Deriving]

class base {private: int private; protected: int protect; public: int public; }; class Derived: Basis // Caution: this is private! {int f1 () {return private; } // that will not do! int f2 () {return protect; } // that works int f3 () {return public; } // this works out }; int main () {Derived from a; Base b; i = a.public; // That goes wrong! i = b.publik; // That works fine. b = a; // Again, that doesn't work. }

restriction

A privately derived class like this one Suffered has the same access options within a member function as with a public inheritance. This can be seen in the three examples of member functions. The difference becomes clear when it comes to external access. You can no longer access the public elements of the base class for the derived object. The compiler also immediately prevents the possibility of assigning an object of the derived classes to an object of the base class.

protected

A derived class does not differ in the access rights from outside from a privately derived class. However, a conversion is still possible within a member function. In practice, inheritance takes place almost exclusively in public. Derivatives marked as or are of little practical use. If you find a use for such inheritance, you should comment the passage extensively.

Elements of the base classes

When a class is derived, the elements of the base class are inherited. If the elements are declared as or, they can be accessed within the derived class in the same way as their own elements. If you define an element in the derived class whose name is already used in the base class, the element of the base class with the same name is covered.

Function call

In some cases, functions of the base class should also be available in the derived class. Only a few lines should be added. Then the function is newly implemented in the derived class and the function of the base class is called directly at the appropriate point in the new function. To be able to call the function of the base class, precede the function name with the name of the base class, separated by two colons.

[Function call of the base class (kasfunc.cpp)]

class tBasis {public: int TuWas (int a); }; class tSpecial case: public tBasis {public: int TuWas (int a); }; int tSpecial case :: TuWas (int a) {int oldValue = tBasis :: TuWas (a); ... return oldValue; }

In the example the function is in the class tSpecial case first the function of the class tBase and then handle the special cases of the derived class.

Constructors and assignment

Cascading constructors

Before the constructor of a derived class is executed, the constructor of the base class is always started. It is the other way around with the destructor. Here the destructor of the base class is called last. This behavior is logical because derived classes build on the properties of the base classes. Accordingly, the base object must be constructed before the constructor of the derived class is called. The same applies to the destructor. The base class destructor must be called last so that the base object is not already destroyed when the derived class is still trying to free the extensions.

Differences in parameters of the constructors

If you derive your class from a base class that does not offer a constructor that has the same parameters as your constructor, then you have to call the constructor of the base class explicitly. You can do that by using an initializer. In the following example, the base class has only one constructor that expects an integer value. This means there is no standard constructor. However, the derived class has a default constructor that the compiler would complain about because it doesn't find a counterpart in the base class. To prevent this from happening, the constructor of the base class is explicitly called as an initializer. When the standard constructor of the derived class is called, the base constructor is called with parameter 5.

[Constructor call (kaskonstrukt.cpp)]

class tBasis {public: tBasis (int i); // no default constructor}; class tSpezialfall: public tBasis {public: tSpezialfall (): tBasis (5) // call the base constructor {...}};

The creation of an object of the type tSpecial case calls the default constructor. Without the initializer, the compiler would use the default constructor of tBase call. However, there is no such thing. The constructor with the integer parameter is explicitly called by the initializer before the initialization of tSpecial case begins.

Copy constructor

If the base class has a copy constructor, this is not automatically inherited. The copy constructor of the base class can be called by an initializer, as the following example shows: tSpezialFall (const tSpezialFall & Objekt): tBasis (Objekt) {...}

Assignment operator

The assignment operator is also not automatically inherited. Typically, the assignment of the base class is called directly as a function, since this is the only way to name the assignment operator of the base class. tSpezialFall & operator = (const tSpezialFall & objekt) {if (this! = & objekt) {// Avoid self-copying! tBasis :: operator = (object); // assign your own elements} return * this; }

Multiple inheritance

syntax

In C ++ it is possible to derive a class from several base classes. After the colon, each individual class is listed with its derivation attribute, separated by a comma. class Auto: public motor, public carriage {...};

Naming conflicts

The car inherits all the properties and functions of a carriage and those of an engine. This could lead to naming conflicts because the programmer of the engine not all names with the author of the class coach will have agreed. Should be the term warehouse occur in both, the name of the base class, separated by two colons, would be prefixed to make the origin clear. class Auto: public motor, public carriage {... a = motor :: camp; ... b = carriage :: camp; ...};

Controversial

There is some dissent in the literature as to whether multiple inheritance makes sense. Programs that use multiple inheritance can easily become confusing and error-prone. (See Kaiser, Richard: C ++ with the Borland C ++ Builder. Springer-Verlag, Berlin-Heidelberg, 2002. S. 811.) That is the reason why some other programming languages ​​do not even allow multiple inheritance.