
The most important slide of the lecture Programming in C++ Session 6 – Inheritance in C++ Dr Christos Kloukinas City, UoL http://staff.city.ac.uk/c.kloukinas/cpp Why use inheritance? (slides originally produced by Dr Ross Paterson) Copyright © 2005 – 2020 Dr Christos Kloukinas (City, UoL) Programming in C++ http://staff.city.ac.uk/c.kloukinas/cpp (slides originallyDr Christos produced Kloukinas by Dr Ross (City, Paterson) UoL) ProgrammingCopyright in C++ © 2005 – 2020 1 / 24 2 / 24 Reasons for Inheritance (revision) Inheritance in C++ Implementation Re-Use Bad-ish. new classes extend existing classes with additional fields and The basic concept is similar to Java, but methods, and can override the definitions of existing methods. different syntax Interface/Type Hierarchies (Is-A relations [*]) Good! the new class is also a subtype of the old: its objects can be used objects of subclasses may be assigned to object variables of wherever objects of the old class can (subtype polymorphism) with superclasses, by slicing off the extra parts. the appropriate method selected by dynamic binding. interactions with: abstract classes declare methods without defining them: the overloading methods are defined in subclasses. pointers [*] vs Has-A relations: template classes A car Is-A vehicle. A car Has-A steering wheel. Dr Christos Kloukinas (City, UoL) Programming in C++ 3 / 24 Dr Christos Kloukinas (City, UoL) Programming in C++ 4 / 24 Inheritance syntax in Java and C++ A base class Recall the class date from session 2: in Java: public class holiday extends date { class date { int day, month, year; in C++: class holiday : public date { public: we will always use public inheritance. date(); // today’s date C++ terminology: date is a base class; date(int d, int m); holiday is a derived class. date(int d, int m, int y); int get_day() const { return day; } multiple inheritance (in C++): int get_month() const { return month; } class child : public parent1, public parent2 { int get_year() const { return year; } there are no interfaces in C++. }; Dr Christos Kloukinas (City, UoL) Programming in C++ 5 / 24 Dr Christos Kloukinas (City, UoL) Programming in C++ 6 / 24 Inheritance and initialization Order of initialization – IMPORTANT! The members of base class(es) are initialized similarly to subobjects: class holiday : public date { Initialization is done in the following order: string name; 1 constructors for base classes public: holiday(string n) : date(), name(n) {} 2 members (in order of declaration) – WARNING!!! BE CAREFULL!!! 3 body of constructor holiday(string n, int d, int m) : The order in which initializers are given has no effect , date(d, m), name(n) {} Danger: so follow the order of declaration. string get_name() const { return name; } Otherwise: The compiler may emit a warning - just in case the order of }; initialisation matters (IN WHICH CASE YOU HAVE A BUG!). Members of the base class can’t be initialized directly: use constructor date (can only use it in the initialisation list!) Dr Christos Kloukinas (City, UoL) Programming in C++ 7 / 24 Dr Christos Kloukinas (City, UoL) Programming in C++ 8 / 24 Initialization and assignment Method overriding in Java and C++ The default in C++ is the opposite to that in Java: As in Java, we can initialize and assign from descendent (derived) in Java: classes, but here objects are copied, not references: final int non_redefinable_method() { ... } holiday h("Anzac Day", 25, 4); int redefinable_method() { ... } date d = h; abstract int undefined_method(); initializes d as a copy of the date part of h. in C++: d = h; int non_redefinable_method() { ... } copies the date part of h into d. virtual int redefinable_method() { ... } virtual int undefined_method() = 0; In both cases, the object is sliced . The latter is called a pure virtual function. When a method is declared virtual in a base class, it is also Note: Call-by-value initialises a new variable, so it also involves copying virtual in derived classes (the keyword there is optional). (and slicing). Why is it the opposite? Dr Christos Kloukinas (City, UoL) Programming in C++ 9 / 24 Dr Christos Kloukinas (City, UoL) Programming in C++ 10 / 24 Method overriding in Java and C++ Programming in C++ The default in C++ is the opposite to that in Java: in Java: final int non_redefinable_method() { ... } int redefinable_method() { ... } abstract int undefined_method(); in C++: Method overriding int non_redefinable_method() { ... } virtual int redefinable_method() { ... } virtual int undefined_method() = 0; Method overriding in Java and C++ The latter is called a pure virtual function. When a method is declared virtual in a base class, it is also virtual in derived classes (the keyword there is optional). 2020-11-30 Overridable methods must be declared virtual: Why is it the opposite? class date { It’s the opposite because non-redefinable member functions are faster ... than redefinable (virtual) ones. (C++’s #1 aim is speed!) virtual string desc() const { ... } }; Redefinable member functions are actually pointers to functions – at run time the code has to dereference the pointer held in the class Overriding in a derived class: information of the current object to figure out which code to execute. This also explains the bizarre syntax for abstract (pure virtual) member class holiday : public date { functions: ... “ = 0” means that the function pointer is the nullptr, i.e., there’s no virtual string desc() const { respective code for it! return name + " " + date::desc(); } }; Note: qualify with the class name to get the base version. Dr Christos Kloukinas (City, UoL) Programming in C++ 11 / 24 Static and dynamic binding Programming in C++ Given functions void print_day1(date d) { cout << "It’s " << d.desc() << ’\n’; } void print_day2(date &d) { Static and dynamic binding cout << "It’s " << d.desc() << ’\n’; } then Given functions holiday xmas("Christmas", 25, 12, 2004); Static and dynamic binding print_day1(xmas); // It’s 25/12/2004 print_day2(xmas); // It’s Christmas 25/12/2004 2020-11-30 Why the different behaviour?! void print_day1(date d) { (the answer is on slide 9) cout << "It’s " << d.desc() << ’\n’; Dynamic Binding } In order to get dynamic binding we need: void print_day2(date &d) { 1 a type hierarchy (inheritance) cout << "It’s " << d.desc() << ’\n’; 2 some virtual member functions } 3 references or pointers to objects then (so that the compiler isn’t sure what the real object type is) holiday xmas("Christmas", 25, 12, 2004); print_day1(xmas); // It’s 25/12/2004 print_day2(xmas); // It’s Christmas 25/12/2004 Why the different behaviour?! (the answer is on slide 9) Dr Christos Kloukinas (City, UoL) Programming in C++ 12 / 24 Abstract classes Derived classes A class containing a pure virtual function is abstract, though this is not class dog : public pet { marked in the syntax. public: dog(string name) : pet(name) {} class pet { string sound() const { return "woof"; } protected: void speak() const { // virtual is optional string _name; pet::speak(); public: cout << ’(’ << _name << " wags tail)\n"; pet(string name) : _name(name) {} } virtual string sound() const = 0; }; virtual void speak() const { cout << _name << ": " << sound() << "!\n"; class cat : public pet { } public: }; cat(string name) : pet(name) {} As in Java, abstract classes may not be instantiated, so no variable virtual string sound() const { return "miao"; } may have type pet, but we can declare a reference (or a pointer). }; Dr Christos Kloukinas (City, UoL) Programming in C++ 13 / 24 Dr Christos Kloukinas (City, UoL) Programming in C++ 14 / 24 Programming in C++ Subtype polymorphism and dynamic binding We cannot pass pets by value, but we can pass them by reference: void speakTwice(const pet &a_pet) { a_pet.speak(); a_pet.speak(); Subtype polymorphism and dynamic binding } Then we can write dog a_dog("Fido"); speakTwice(a_dog); Subtype polymorphism and dynamic binding cat a_cat("Tiddles"); speakTwice(a_cat); pet 2020-11-30 We cannot pass s by value, but we can pass them by reference: Why can’t we pass a pet by value to speakTwice ? void speakTwice(const pet &a_pet) { a_pet.speak(); Because a_pet.speak(); call-by-value involves creating a new local object that is initialised using } the original parameter (see slide 9); and a_pet is an abstract class, so we cannot instantiate it. Then we can write dog a_dog("Fido"); speakTwice(a_dog); cat a_cat("Tiddles"); speakTwice(a_cat); Why can’t we pass a pet by value to speakTwice ? Dr Christos Kloukinas (City, UoL) Programming in C++ 15 / 24 Programming in C++ Caution: inheritance and overloading class A { virtual void f(int n, Point p) { ... } }; Now suppose we intend to override f in a derived class, but make a Caution: inheritance and overloading mistake with the argument types: class B : public A { void f(Point p, int n) { ... } Caution: inheritance and overloading }; f will be accepted as a definition of a new and different member function. 2020-11-30 Even forgetting a single const or changing a * to a & means it’s a class A { different function! virtual void f(int n, Point p) { ... } }; How can you protect yourself against such mistakes? Now suppose we intend to override f in a derived class, but make a Since C++11 there’s a new keyword override that you can use to mistake with the argument types: state that you’re trying to override a member function of one of your base classes: class B : public A { void f(Point p, int n) { ... } class B : public A { }; void f(Point p, int n) override { ... } // Now the compiler catches the error }; f will be accepted as a definition of a new and different member There’s also a keyword final to state that derived classes should function. not be allow to further override the member function: Even forgetting a single const or changing a to a & means it’s a * class A { different function! virtual void f(int n, Point p) { ... } Dr Christos Kloukinas (City, UoL) Programming in C++ 16 / 24 virtual int g(Point p) const { ..
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages9 Page
-
File Size-