<<

QUIZ

How could we disable the automatic creation of copy- constructors pre-C++11? What syntax feature did C++11 introduce to make the disabling clearer and more permanent? • Give a code example.

QUIZ

How is the overloaded assignment operator different from all other overloaded operators in C++? QUIZ

Show in a code example how to disable the automatic creation of the overloaded assignment operator post- C++11. The class is named Foo. Ch. 14: Inheritance & Composition Remember composition Composition

If embedded object is private, it will be accessed through member (or friend) functions Composition – multi-level example

Draw the UML diagram, as learned in ch.1!

Inheritance Base class, from which Y inherits

UML diagram Inheritance The default is private inheritance

During inheritance, everything defaults to private. If the base class were not preceded by public, it would mean that all of the members of the base class, private and public would be private in the derived class.

Examples on next slide Explaining public and private in inheritance (see protected later!) Inheritance – adding new functions

change( ) ↔ we can add completely new functions. Inheritance – redefining functions

set( ) ↔ we can redefine functions from the base class.

If function is redefined, we can still call the base-class version using the resolution operator! Inheritance – redefining functions

A note on language: redefining functions in a derived class is mostly referred to today as overriding; this includes the C++ standards. (Redefining is used when we talk about typedef or namespaces.) Unfortunately, the matter is further muddled by the existence of the override identifier (since C++11 – it applies only to virtual functions).

Does this colon remind us of something? Answer: The constructor initializer list

Indeed, the constructor initializer list is used to initialize the members of the parent class!

Example on next slide Using the constructor initializer list to initialize members of the parent class Using the constructor initializer list to initialize members of the parent class

There’s no way to get to the opening brace of the constructor without some constructor being called for all the member objects and base-class objects, even if the compiler must make a hidden call to a default constructor. text This is a further enforcement of the C++ guarantee that no object (or part of an object) can get out of the starting gate without its constructor being called. Automatic destructor calls Although you are often required to make explicit constructor calls in the initializer list, you never need to make explicit destructor calls because there’s only one destructor for any class, and it doesn’t take any arguments.

However, the compiler still ensures that all destructors text are called, and that means all of the destructors in the entire hierarchy, starting with the most-derived (bottom) destructor and working up to the root. Automatic destructor calls Note well: Constructors and destructors are quite unusual in that every one in the hierarchy is called,

text whereas with a normal member function only that function is called, but not any of the base- class versions. QUIZ Write a constructor for class Bar that initializes the data member and announces itself. Solution Declare a class MyType2 derived from Bar that has a new private data QUIZ member of type integer, m. Solution QUIZ

Write a constructor for MyType2 that initializes i with a value, and m with the same value incremented by one. Solutions QUIZ

Can Bar’s constructor also be moved from the initializer list inside the body? Solution

In other words: “It’s too late!”  QUIZ

Write a print() member function for MyType2 that prints both i and m. Solution

User code on next slide EOL 1 Order of constructor & destructor calls

If an object has several sub-objects, each of them possibly with sub-objects of their own: • construction starts at the very root of the class hierarchy • at each level, the base class constructor is called first, followed by the member object constructors. The destructors are called in exactly the reverse order of the constructors.

example First, let’s grok the macro used to define classes in the program C14:Order.cpp

It has to be only one logical line for the preprocessor!

"Stringification Operator" converts a token into a string, escaping any quotes or backslashes.

Write the expanded form when ID is replaced with Base1 by the preprocessor! First, let’s grok the macro used to define classes in the program C14:Order.cpp

Placeholder argument avoids default constructor!

Remember character array concatenation from ch.2! First, let’s grok the macro used to define classes in the program C14:Order.cpp

Some programmers like to put it here, so the code looks like a valid class declaration, but it adds to …

Innocuous here, but can cause problems before else statement, since it counts as a null statement. It is considered best practice to “swallow the semicolon”. This is one of the many reasons why macros are tricky!

This is an economical way to create many similar classes with diferent names (for testing purposes). Now let’s see the derived classes in the program C14:Order.cpp

Draw the UML diagram! Now let’s see the derived classes in the program C14:Order.cpp Now let’s see the derived classes in the program C14:Order.cpp Name hiding

If you inherit a class and provide a new definition for one of its member functions, the function from the base class is hidden. If the function was overloaded in the base class, all the text overloaded versions are hidden. (This happens whether we provide the exact signature and return type or not.)

examples Redefinition, so g() from the base class is hidden Hides both overloaded f() functions from the base! However, it’s still possible to access the overloaded f() from the base using the scope-resolution operator! Return value does not make a difference; just like derived2, it hides both overloaded f() functions from the base! Argument type does not make a difference; just like derived2, it hides both overloaded f() functions from the base! Functions that don’t automatically inherit

Language twist: What is meant is that the functions are not automatically inherited. 1. Constructors and destructors deal with the creation and destruction of an object, and they can know what to do with the aspects of the object only for their particular class, so all the constructors and destructors in the hierarchy below them must be called. Thus, they are not inherited, and must be created specially for each derived class. Functions that don’t automatically inherit

2. The operator= doesn’t inherit either, because it performs a constructor-like activity. In lieu of inheritance, these functions are synthesized by the compiler if you don’t create them yourself, using memberwise initialization and memberwise assignment, respectively (as described in Chapters 11 and 12). Inheritance and static member functions

As far as inheritance is concerned, static member functions act the same as non-static ones:

• They are inherited automatically into the derived class. • If you redefine a static member, all the other overloaded functions in the base class are hidden. protected

In an ideal world, private members would always be hard-and-fast private, but in real projects there are times when you want to make something hidden from the world at large and yet allow access for members of text derived classes. The protected keyword is a nod to pragmatism; it says, “This is private as far as the class user is concerned, but available to anyone who inherits from this class.”

Example on next slide No need for public inheritance anymore, we can be more selective and allow the derived class access to only those members of the base class that are really needed. This makes the code safer! Individual work for next time: • Read and understand the section Combining composition & inheritance • End-of-chapter exercises 1, 2

EOL 2 QUIZ: Explain how methods are hidden during inheritance QUIZ: Explain how methods are hidden during inheritance

Solution

If we redefine a member function foo, all the overloaded member functions foo in the base class are hidden. Important application of inheritance: subtyping

Example:

We want to create a type of ifstream object that not only opens a file but also keeps track of the name of the file.

We try to use composition and embed both an ifstream and a string into the new class: …. Unfortunately, we run into this problem: The member functions of the embedded objects are not immediately available, e.g. we need to say Solution: Derive a class from ifstream Added benefit: non-member functions like getline( ) that expect an ifstream can also work with an FName2. That’s because an FName2 is a type of ifstream; it doesn’t just contain one!

This is called … Upcasting

The relationship between the child class and parent class Parent (base) can be summarized by class saying, “The child class is a type of the parent class.” Child (derived) class Upcasting and the copy-constructor Draw the UML class diagram! No explicit copy-constructor! QUIZ In what order are the initializations performed when a Child object is created?

How does the compiler synthesize the copy-constructor?

As expected, top-down:

Conclusion: If you allow the compiler to synthesize a copy-constructor for a derived class, it will automatically call the base-class copy- constructor, and then the copy-constructors for all the member objects (or perform a bitcopy on built-in types) Extra-credit

EOL 3 SKIP & inheritance Deleted functions & inheritance

Not in text. Only applies to C++11 and later. Deleted functions & inheritance

Not in text. Only applies to C++11 and later. A philosophical note …

Changes that can be made in a derived class: • • •

Think of biological evolution … Multiple inheritance (MI)

[…] inherit from more than one class at a time. Indeed you can, but whether it makes sense as part of a design is a subject of continuing debate. One thing is generally agreed upon: You shouldn’t try text this until you’ve been programming quite a while and understand the language thoroughly. Typical use of MI

Remember subtyping … What if we need the functionality from two (or more) existing classes, each fairly complex? • In the literature, this is known as combining libraries.

Example on next slides

MI opens the possibility of many ambiguities, e.g. what if both base classes have members (data or/and functions) with the same name?

See vol.2 of our text for details. You turn!

Declare a class C that inherits from both A and B. Create a C object in the main program. Solution

Source: http://www.geeksforgeeks.org/multiple-inheritance-in-c/ Incremental development

One of the advantages of inheritance and composition is that these support incremental development by allowing you to introduce new code without causing bugs in existing code. If bugs do appear, they are isolated within the new code. Incremental development

By inheriting from (or composing with) an existing class, […] you leave the existing code – that someone else may still be using – untouched and unbugged. If a bug happens, you know it’s in your new code, which is much shorter and easier to read than if you had modified the body of existing code. Individual work for next time: Read the subsections • Choosing composition vs. inheritance • Composition vs. inheritance (revisited) • Pointer & reference upcasting • A crisis

Demonstrates the need for polymorphism Homework for ch. 14

Provided as separate handout (also available on our webpage --> agapie.net) Due Friday, Apr.27, at the beginning of class. Please hand in a hard-copy, do not email!

EOL 4 The following slides cover more nitty-gritty rules on inheritance.

These are provided FYI only, not for exam!