C++ Inheritance II, Casting CSE 333 Summer 2018

Slides:



Advertisements
Similar presentations
. Virtual Classes & Polymorphism. Example (revisited) u We want to implement a graphics system u We plan to have lists of shape. Each shape should be.
Advertisements

Lecture 3 Feb 4 summary of last week’s topics and review questions (handout) Today’s goals: Chapter 1 overview (sections 1.4 to 1.6) c++ classes constructors,
Polymorphism, Virtual Methods and Abstract Classes.
Rossella Lau Lecture 8, DCO10105, Semester B, DCO10105 Object-Oriented Programming and Design  Lecture 8: Polymorphism & C++ pointer  Inheritance.
C++ Training Datascope Lawrence D’Antonio Lecture 1 Quiz 1.
1 CSE 303 Lecture 24 Inheritance in C++, continued slides created by Marty Stepp
CSE 332: C++ Classes From Procedural to Object-oriented Programming Procedural programming –Functions have been the main focus so far Function parameters.
Computer Science and Software Engineering University of Wisconsin - Platteville 7. Inheritance and Polymorphism Yan Shi CS/SE 2630 Lecture Notes.
LECTURE LECTURE 17 More on Templates 20 An abstract recipe for producing concrete code.
CSE 425: Object-Oriented Programming II Implementation of OO Languages Efficient use of instructions and program storage –E.g., a C++ object is stored.
“is a”  Define a new class DerivedClass which extends BaseClass class BaseClass { // class contents } class DerivedClass : BaseClass { // class.
CSE 332: C++ templates This Week C++ Templates –Another form of polymorphism (interface based) –Let you plug different types into reusable code Assigned.
1 Chapter 10: Data Abstraction and Object Orientation Aaron Bloomfield CS 415 Fall 2005.
1 Inheritance We are modeling the operation of a transportation company that uses trains and trucks to transfer goods. A suitable class hierarchy for the.
Programming Languages and Paradigms Object-Oriented Programming (Part II)
Object Oriented Programming with C++/ Session 6 / 1 of 44 Multiple Inheritance and Polymorphism Session 6.
1 Inheritance. 2 Why use inheritance?  The most important aspect of inheritance is that it expresses a relationship between the new class and the base.
Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run.
Chapter 9 Questions 1. What are the difference between constructors and member functions? 2. Design and implement a simple class as you want, with constructors.
CS212: Object Oriented Analysis and Design Lecture 17: Virtual Functions.
CS-1030 Dr. Mark L. Hornick 1 Basic C++ State the difference between a function/class declaration and a function/class definition. Explain the purpose.
Chapter 8 Class Inheritance and Interfaces F Superclasses and Subclasses  Keywords: super F Overriding methods  The Object Class  Modifiers: protected,
Inheritance Initialization & Destruction of Derived Objects Protected Members Non-public Inheritance Virtual Function Implementation Virtual Destructors.
Inheritance and Composition Reusing the code and functionality Unit - 04.
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
Abstract Classes & Object Slicing. Pure Virtual Functions Virtual Function : Child class may override, if working with pointer/reference, check to see.
Overview of C++ Polymorphism
Chapter 1 C++ Basics Review (Section 1.4). Classes Defines the organization of a data user-defined type. Members can be  Data  Functions/Methods Information.
Recap Introduction to Inheritance Inheritance in C++ IS-A Relationship Polymorphism in Inheritance Classes in Inheritance Visibility Rules Constructor.
Polymorphism and Virtual Functions One name many shapes behaviour Unit - 07.
Class Inheritance Inheritance as an is-a relationship Public derive one class from another Protected access Initializer lists in constructor Upcasting.
CSC241 Object-Oriented Programming (OOP) Lecture No. 17.
Computer Science Department Inheritance & Polymorphism.
CSE 374 Programming Concepts & Tools Hal Perkins Fall 2015 Lecture 20 – C++ Subclasses and Inheritance.
CS 342: C++ Overloading Copyright © 2004 Dept. of Computer Science and Engineering, Washington University Overview of C++ Overloading Overloading occurs.
CSE 332: C++ Overloading Overview of C++ Overloading Overloading occurs when the same operator or function name is used with different signatures Both.
C++ Functions A bit of review (things we’ve covered so far)
Abstract Classes & Object Slicing. Object Slicing.
Design issues for Object-Oriented Languages
Inheritance Modern object-oriented (OO) programming languages provide 3 capabilities: encapsulation inheritance polymorphism which can improve the design,
Polymorphism, Virtual Methods and Abstract Classes
7. Inheritance and Polymorphism
Motivation and Overview
Inheritance & Polymorphism
Inheritance, Polymorphism and the Object Memory Model
C++ Inheritance II, Casting CSE 333 Spring 2018
Chapter 9 Inheritance and Polymorphism
C++ Constructor Insanity CSE 333 Spring 2018
C++ Inheritance I CSE 333 Spring 2018
Polymorphism Professor Hugh C. Lauer CS-2303, System Programming Concepts (Slides include materials from The C Programming Language, 2nd edition, by Kernighan.
Lecture 5 Inheritance, Polymorphism, Object Memory Model, The Visitor Pattern …and gazillion other tidbits!
CISC/CMPE320 - Prof. McLeod
C++ Inheritance II, Casting CSE 333 Summer 2018
C++ Inheritance I CSE 333 Summer 2018
C++ Class Details, Heap CSE 333 Autumn 2018
C++ Constructor Insanity CSE 333 Summer 2018
Overview of C++ Polymorphism
Inheritance, Polymorphism and the Object Memory Model
C++ Inheritance I CSE 333 Autumn 2018
Java Programming Language
C++ Templates CSE 333 Autumn 2018
C++ Constructor Insanity CSE 333 Autumn 2018
C++ Inheritance II, Casting CSE 333 Winter 2019
C++ Constructor Insanity CSE 333 Winter 2019
References Revisited CSE 333 Autumn 2018
References Revisited CSE 333 Winter 2019
C++ Inheritance I CSE 333 Winter 2019
C++ Templates CSE 333 Winter 2019
C++ Constructor Insanity CSE 333 Spring 2019
SPL – PS3 C++ Classes.
Presentation transcript:

C++ Inheritance II, Casting CSE 333 Summer 2018 Instructor: Hal Perkins Teaching Assistants: Tarkan Al-Kazily Renshu Gu Travis McGaha Harshita Neti Thai Pham Forrest Timour Soumya Vasisht Yifan Xu

Administrivia Inheritance exercise out today, due Friday morning hw3 due in a week, Thursday 11/15 Sections this week: how to debug disk files and other hw3 things + more! Be there!!

Lecture Outline C++ Inheritance C++ Casting Static Dispatch Abstract Classes Constructors and Destructors Assignment C++ Casting Reference: C++ Primer, Chapter 15

What happens if we omit “virtual”? By default, without virtual, methods are dispatched statically At compile time, the compiler writes in a call to the address of the class’ method in the .text segment Based on the compile-time visible type of the callee This is different than Java class Derived : public Base { ... }; int main(int argc, char** argv) { Derived d; Derived* dp = &d; Base* bp = &d; dp->foo(); bp->foo(); return 0; } Derived::foo() ... Base::foo() ...

Static Dispatch Example Removed virtual on methods: Stock.h double Stock::GetMarketValue() const; double Stock::GetProfit() const; DividendStock dividend(); DividendStock* ds = &dividend; Stock* s = &dividend; // Invokes DividendStock::GetMarketValue() ds->GetMarketValue(); // Invokes Stock::GetMarketValue() s->GetMarketValue(); // invokes Stock::GetProfit(), since that method is inherited. // Stock::GetProfit() invokes Stock::GetMarketValue(). ds->GetProfit(); // invokes Stock::GetProfit(). // Stock::GetProfit() invokes Stock::GetMarketValue(). s->GetProfit();

virtual is “sticky” If X::f() is declared virtual, then a vtable will be created for class X and for all of its subclasses The vtables will include function pointers for (the correct) f f() will be called using dynamic dispatch even if overridden in a derived class without the virtual keyword Good style to help the reader and avoid bugs by using override Style guide controversy, if you use override should you use virtual in derived classes? Recent style guides say just use override, but you’ll sometimes see both, particularly in older code

Why Not Always Use virtual? Two (fairly uncommon) reasons: Efficiency: Non-virtual function calls are a tiny bit faster (no indirect lookup) A class with no virtual functions has objects without a vptr field Control: If f() calls g() in class X and g is not virtual, we’re guaranteed to call X::g() and not g() in some subclass Particularly useful for framework design In Java, all methods are virtual, except static class methods, which aren’t associated with objects In C++ and C#, you can pick what you want Omitting virtual can cause obscure bugs

Mixed Dispatch Example 5/9/2018 Mixed Dispatch Example mixed.cc void main(int argc, char** argv) { A a; B b; A* a_ptr_a = &a; A* a_ptr_b = &b; B* b_ptr_a = &a; B* b_ptr_b = &b; a_ptr_a->m1(); // a_ptr_a->m2(); // a_ptr_b->m1(); // a_ptr_b->m2(); // b_ptr_b->m1(); // b_ptr_b->m2(); // } class A { public: // m1 will use static dispatch void m1() { cout << "a1, "; } // m2 will use dynamic dispatch virtual void m2() { cout << "a2"; } }; class B : public A { void m1() { cout << "b1, "; } // m2 is still virtual by default void m2() { cout << "b2"; } a_ptr_a->m1(); // a1, a_ptr_a->m2(); // a2 a_ptr_b->m1(); // a1, a_ptr_b->m2(); // b2 b_ptr_b->m1(); // b1, b_ptr_b->m2(); // b2

Mixed Dispatch Example 5/9/2018 Mixed Dispatch Example mixed.cc void main(int argc, char** argv) { A a; B b; A* a_ptr_a = &a; A* a_ptr_b = &b; B* b_ptr_a = &a; B* b_ptr_b = &b; a_ptr_a->m1(); // a1 a_ptr_a->m2(); // a2 a_ptr_b->m1(); // a1 a_ptr_b->m2(); // b2 b_ptr_b->m1(); // b1 b_ptr_b->m2(); // b2 } class A { public: // m1 will use static dispatch void m1() { cout << "a1, "; } // m2 will use dynamic dispatch virtual void m2() { cout << "a2"; } }; class B : public A { void m1() { cout << "b1, "; } // m2 is still virtual by default void m2() { cout << "b2"; } a_ptr_a->m1(); // a1, a_ptr_a->m2(); // a2 a_ptr_b->m1(); // a1, a_ptr_b->m2(); // b2 b_ptr_b->m1(); // b1, b_ptr_b->m2(); // b2

Your Turn! Whose Foo() is called? Q1 Q2 A A B B D D ??? test.cc class A { public: void Foo(); }; class B : public A { virtual void Foo(); class C : public B { class D : public C { class E : public C { void Bar() { D d; E e; A* a_ptr = &d; C* c_ptr = &e; // Q1: a_ptr->Foo(); // Q2: c_ptr->Foo(); }

Abstract Classes Sometimes we want to include a function in a class but only implement it in derived classes In Java, we would use an abstract method In C++, we use a “pure virtual” function Example: virtual string noise() = 0; A class containing any pure virtual methods is abstract You can’t create instances of an abstract class Extend abstract classes and override methods to use them A class containing only pure virtual methods is the same as a Java interface Pure type specification without implementations virtual string noise() = 0;

Lecture Outline C++ Inheritance C++ Casting Static Dispatch Abstract Classes Constructors and Destructors Assignment C++ Casting Reference: C++ Primer, Chapter 15

Derived-Class Objects A derived object contains “subobjects” corresponding to the data members inherited from each base class No guarantees about how these are laid out in memory (not even contiguousness between subobjects) Conceptual structure of DividendStock object: members inherited from Stock symbol_ total_shares_ total_cost_ current_price_ members defined by DividendStock dividends_

Constructors and Inheritance A derived class does not inherit the base class’ constructor The derived class must have its own constructor A synthesized default constructor for the derived class first invokes the default constructor of the base class and then initialize the derived class’ member variables Compiler error if the base class has no default constructor The base class constructor is invoked before the constructor of the derived class You can use the initialization list of the derived class to specify which base class constructor to use

Constructor Examples badctor.cc goodctor.cc 5/9/2018 Constructor Examples badctor.cc goodctor.cc class Base { // no default ctor public: Base(int y) : y(y) { } int y; }; // Compiler error when you try to // instantiate a Der1, as the // synthesized default ctor needs // to invoke Base's default ctor. class Der1 : public Base { int z; class Der2 : public Base { Der2(int y, int z) : Base(y), z(z) { } // has default ctor class Base { public: int y; }; // works now class Der1 : public Base { int z; // still works class Der2 : public Base { Der2(int z) : z(z) { } Run in gdb to show subobject.

Destructors and Inheritance 5/9/2018 Destructors and Inheritance baddtor.cc Destructor of a derived class: First runs body of the dtor Then invokes of the dtor of the base class Static dispatch of destructors is almost always a mistake! Good habit to always define a dtor as virtual Empty body if there’s no work to do class Base { public: Base() { x = new int; } ~Base() { delete x; } int* x; }; class Der1 : public Base { Der1() { y = new int; } ~Der1() { delete y; } int* y; void foo() { Base* b0ptr = new Base; Base* b1ptr = new Der1; delete b0ptr; // OK delete b1ptr; // leaks Der1::y } Run code to show printouts of ctor & dtor calls.

Assignment and Inheritance 5/9/2018 Assignment and Inheritance C++ allows you to assign the value of a derived class to an instance of a base class Known as object slicing It’s legal since b=d passes type checking rules But b doesn’t have space for any extra fields in d slicing.cc class Base { public: Base(int x) : x_(x) { } int x_; }; class Der1 : public Base { Der1(int y) : Base(16), y_(y) { } int y_; void foo() { Base b(1); Der1 d(2); d = b; // compiler error b = d; // what happens to y_? } d = b; // compiler error b = d; // what happens to y?

STL and Inheritance Recall: STL containers store copies of values 5/9/2018 STL and Inheritance Recall: STL containers store copies of values What happens when we want to store mixes of object types in a single container? (e.g. Stock and DividendStock) You get sliced  #include <list> #include "Stock.h" #include "DividendStock.h" int main(int argc, char** argv) { Stock s; DividendStock ds; list<Stock> li; li.push_back(s); // OK li.push_back(ds); // OUCH! return 0; }

5/9/2018 STL and Inheritance Instead, store pointers to heap-allocated objects in STL containers No slicing!  sort() does the wrong thing  You have to remember to delete your objects before destroying the container  Smart pointers!

Lecture Outline C++ Inheritance C++ Casting Static Dispatch Abstract Classes Constructors and Destructors Assignment C++ Casting Reference: C++ Primer §4.11.3, 19.2.1

Explicit Casting in C Simple syntax: lhs = (new_type) rhs; Used to: Convert between pointers of arbitrary type Don’t change the data, but treat differently Forcibly convert a primitive type to another Actually changes the representation You can still use C-style casting in C++, but sometimes the intent is not clear lhs = (new_type) rhs;

Casting in C++ C++ provides an alternative casting style that is more informative: static_cast<to_type>(expression) dynamic_cast<to_type>(expression) const_cast<to_type>(expression) reinterpret_cast<to_type>(expression) Always use these in C++ code Intent is clearer Easier to find in code via searching

static_cast static_cast can convert: 5/9/2018 staticcast.cc static_cast class A { public: int x; }; class B { float x; class C : public B { char x; static_cast can convert: Pointers to classes of related type Compiler error if classes are not related Dangerous to cast down a class hierarchy Non-pointer conversion e.g. float to int static_cast is checked at compile time void foo() { B b; C c; // compiler error A* aptr = static_cast<A*>(&b); // OK B* bptr = static_cast<B*>(&c); // compiles, but dangerous C* cptr = static_cast<C*>(&b); } No run time checks on conversion. Does not incur the overhead of type-safety checks of dynamic_cast. Works with any well-defined type conversion

dynamic_cast dynamic_cast can convert: 5/9/2018 dynamiccast.cc dynamic_cast class Base { public: virtual void foo() { } float x; }; class Der1 : public Base { char x; dynamic_cast can convert: Pointers to classes of related type References to classes of related type dynamic_cast is checked at both compile time and run time Casts between unrelated classes fail at compile time Casts from base to derived fail at run time if the pointed-to object is not the derived type void bar() { Base b; Der1 d; // OK (run-time check passes) Base* bptr = dynamic_cast<Base*>(&d); assert(bptr != nullptr); Der1* dptr = dynamic_cast<Der1*>(bptr); assert(dptr != nullptr); // Run-time check fails, returns nullptr bptr = &b; dptr = dynamic_cast<Der1*>(bptr); } virtual foo() function needed to make Base polymorphic. dynamic_cast can do pointer upcast (same as implicit conversion). dynamic_cast can do pointer downcast only for polymorphic classes. Requires Run-Time Type Information (RTTI).

const_cast const_cast adds or strips const-ness Dangerous (!) void foo(int* x) { *x++; } void bar(const int* x) { foo(x); // compiler error foo(const_cast<int*>(x)); // succeeds int main(int argc, char** argv) { int x = 7; bar(&x); return 0;

reinterpret_cast reinterpret_cast casts between incompatible types Low-level reinterpretation of the bit pattern e.g. storing a pointer in an int, or vice-versa Works as long as the integral type is “wide” enough Converting between incompatible pointers Dangerous (!) This is used (carefully) in hw3

Implicit Conversion The compiler tries to infer some kinds of conversions When types are not equal and you don’t specify an explicit cast, the compiler looks for an acceptable implicit conversion void bar(std::string x); void foo() { int x = 5.7; // conversion, float -> int bar("hi"); // conversion, (const char*) -> string char c = x; // conversion, int -> char }

Sneaky Implicit Conversions (const char*) to string conversion? If a class has a constructor with a single parameter, the compiler will exploit it to perform implicit conversions At most, one user-defined implicit conversion will happen Can do int → Foo, but not int → Foo → Baz class Foo { public: Foo(int x) : x(x) { } int x; }; int Bar(Foo f) { return f.x; } int main(int argc, char** argv) { return Bar(5); // equivalent to return Bar(Foo(5));

Avoiding Sneaky Implicits Declare one-argument constructors as explicit if you want to disable them from being used as an implicit conversion path Usually a good idea class Foo { public: explicit Foo(int x) : x(x) { } int x; }; int Bar(Foo f) { return f.x; } int main(int argc, char** argv) { return Bar(5); // compiler error

Extra Exercise #1 Design a class hierarchy to represent shapes e.g. Circle, Triangle, Square Implement methods that: Construct shapes Move a shape (i.e. add (x,y) to the shape position) Returns the centroid of the shape Returns the area of the shape Print(), which prints out the details of a shape

Extra Exercise #2 Implement a program that uses Extra Exercise #1 (shapes class hierarchy): Constructs a vector of shapes Sorts the vector according to the area of the shape Prints out each member of the vector Notes: Avoid slicing! Make sure the sorting works properly!