QUIZ How could we disable the automatic creation of copyconstructors pre-c++11? What syntax feature did C++11 introduce to make the disabling clearer and more permanent? Give a code example.
Ch. 14: Inheritance & Composition
Remember composition
Composition If embedded object is private, it will be accessed through member (or friend) functions
Draw the UML diagram, as learned in ch.1! Composition multi-level example
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 scope 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
text 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. 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.
text 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 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.
text Automatic destructor calls Note well: Constructors and destructors are quite unusual in that every one in the hierarchy is called, whereas with a normal member function only that function is called, but not any of the baseclass 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 member of type integer, m. QUIZ
Solution
QUIZ Write a constructor for MyType2 that initializes i with a value, and m with the same value incremented by one.
Solutions
Can Bar s constructor also be moved from the initializer list inside the body? QUIZ
In other words: It s too late! Solution
QUIZ Write a print() member function for MyType2 that prints both i and m.
User code on next slide Solution
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
text 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 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!
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.
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 Refers to ch.12, which we haven t covered yet! 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.
text 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 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!
Important application of inheritance: Example: subtyping 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 can be summarized by saying, The child class is a type of the parent class. Parent (base) class Child (derived) class
Upcasting and the copy-constructor The overloaded << operator refers to ch.12, which we haven t covered yet!
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 copyconstructor, and then the copy-constructors for all the member objects (or perform a bitcopy on built-in types)
Extra-credit EOL 3
SKIP Operator overloading & 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
text 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 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.
Source: http://www.geeksforgeeks.org/multiple-inheritance-in-c/ Solution
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.
Incremental development It s rather amazing how cleanly the classes are separated. You don t even need the source code for the member functions in order to reuse the code, just the header file describing the class and the object file or library file with the compiled member functions. Indeed, we may not even have the source code remember handle classes and opaque pointers from ch.5!
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 Wednesday, Nov.29, 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!