Introduction to Object-Oriented Programming
Total Page:16
File Type:pdf, Size:1020Kb
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 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 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 Operator overloading & inheritance Deleted functions & inheritance Not in text. Only applies to C++11 and later.