Object-Oriented Programming, Iouliia Skliarova

Similar documents
Object-Oriented Programming, Iouliia Skliarova

Object-Oriented Programming, Iouliia Skliarova

What is Polymorphism? Quotes from Deitel & Deitel s. Why polymorphism? How? How? Polymorphism Part 1

Polymorphism Part 1 1

Polymorphism. Miri Ben-Nissan (Kopel) Miri Kopel, Bar-Ilan University

G52CPP C++ Programming Lecture 13

15: Polymorphism & Virtual Functions

C++ Crash Kurs. Polymorphism. Dr. Dennis Pfisterer Institut für Telematik, Universität zu Lübeck

QUIZ. Write the following for the class Bar: Default constructor Constructor Copy-constructor Overloaded assignment oper. Is a destructor needed?

Object Oriented Software Design II

Object Oriented Software Design II

VIRTUAL FUNCTIONS Chapter 10

OOPS Viva Questions. Object is termed as an instance of a class, and it has its own state, behavior and identity.

CMSC 202 Section 010x Spring Justin Martineau, Tuesday 11:30am

OBJECT ORIENTED PROGRAMMING USING C++ CSCI Object Oriented Analysis and Design By Manali Torpe

QUIZ. How could we disable the automatic creation of copyconstructors

QUIZ. How could we disable the automatic creation of copyconstructors

C++ Important Questions with Answers

Inheritance, Polymorphism and the Object Memory Model

Inheritance, and Polymorphism.

Software Paradigms (Lesson 3) Object-Oriented Paradigm (2)

Data type of a pointer must be same as the data type of the variable to which the pointer variable is pointing. Here are a few examples:

Object Oriented Programming: Inheritance Polymorphism

C++ Addendum: Inheritance of Special Member Functions. Constructors Destructor Construction and Destruction Order Assignment Operator

OOP THROUGH C++(R16) int *x; float *f; char *c;

Polymorphism. Zimmer CSCI 330

04-24/26 Discussion Notes

POLYMORPHISM Polymorphism: the type Polymorphism taking many shapes type of object

CS105 C++ Lecture 7. More on Classes, Inheritance

What are the characteristics of Object Oriented programming language?

Absolute C++ Walter Savitch

G52CPP C++ Programming Lecture 7. Dr Jason Atkin

CS32 - Week 4. Umut Oztok. Jul 15, Umut Oztok CS32 - Week 4

Midterm Review. PIC 10B Spring 2018

Fast Introduction to Object Oriented Programming and C++

Cpt S 122 Data Structures. Course Review Midterm Exam # 2

Module 10 Inheritance, Virtual Functions, and Polymorphism

Introduction to C++ Introduction to C++ Dr Alex Martin 2013 Slide 1

Computer Programming Inheritance 10 th Lecture

The object-oriented approach goes a step further by providing tools for the programmer to represent elements in the problem space.

1: Introduction to Object (1)

C++ Inheritance and Encapsulation

Inheritance and Polymorphism

Chapter 15: Inheritance, Polymorphism, and Virtual Functions

C++ Inheritance and Encapsulation

Object-Oriented Programming. Lecture 4 Dr Piotr Cybula

Pointers. 1 Background. 1.1 Variables and Memory. 1.2 Motivating Pointers Massachusetts Institute of Technology

Increases Program Structure which results in greater reliability. Polymorphism

Ch02. True/False Indicate whether the statement is true or false.

CS250 Final Review Questions

OOP Fundamental Concepts

Inheritance, Polymorphism, and Interfaces

ECE 3574: Dynamic Polymorphism using Inheritance

Java Object Oriented Design. CSC207 Fall 2014

COEN244: Polymorphism

Inheritance. OOP components. Another Example. Is a Vs Has a. Virtual Destructor rule. Virtual Functions 4/13/2017

Lecture 15a Persistent Memory & Shared Pointers

C++ Inheritance I. CSE 333 Spring Instructor: Justin Hsia

AIMS Embedded Systems Programming MT 2017

OBJECT ORIENTED PROGRAMMING USING C++

Advanced Systems Programming

END TERM EXAMINATION

COMP 2355 Introduction to Systems Programming

C++ Programming: Polymorphism

G52CPP C++ Programming Lecture 9

The issues. Programming in C++ Common storage modes. Static storage in C++ Session 8 Memory Management

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Introduction to C++ Part II. Søren Debois. Department of Theoretical Computer Science IT University of Copenhagen. September 12th, 2005

CS 162, Lecture 25: Exam II Review. 30 May 2018

Day 4. COMP1006/1406 Summer M. Jason Hinek Carleton University

Short Notes of CS201

Why use inheritance? The most important slide of the lecture. Programming in C++ Reasons for Inheritance (revision) Inheritance in C++

Ch. 11: References & the Copy-Constructor. - continued -

What does it mean by information hiding? What are the advantages of it? {5 Marks}

CS201 - Introduction to Programming Glossary By

G52CPP C++ Programming Lecture 14. Dr Jason Atkin

Instantiation of Template class

CE221 Programming in C++ Part 1 Introduction

Inheritance and Interfaces

Semantics of C++ Hauptseminar im Wintersemester 2009/10 Templates

CS 376b Computer Vision

C++ for numerical computing

Polymorphism 8. Polymorphism. Content. Normal Member Functions Accessed with Pointers. Polymorphism. Virtual Members Abstract Class

CS 251 INTERMEDIATE SOFTWARE DESIGN SPRING C ++ Basics Review part 2 Auto pointer, templates, STL algorithms

Chapter 1: Object-Oriented Programming Using C++

UNIVERSITI TEKNIKAL MALAYSIA MELAKA FACULTY INFORMATION TECHNOLOGY AND COMMUNICATION (FTMK) BITE 1513 GAME PROGRAMMING I.

1/29/2011 AUTO POINTER (AUTO_PTR) INTERMEDIATE SOFTWARE DESIGN SPRING delete ptr might not happen memory leak!

CREATED BY: Muhammad Bilal Arslan Ahmad Shaad. JAVA Chapter No 5. Instructor: Muhammad Naveed

Programming Language Concepts Object-Oriented Programming. Janyl Jumadinova 28 February, 2017

G52CPP C++ Programming Lecture 12

CS250 Final Review Questions

Resource Management With a Unique Pointer. Resource Management. Implementing a Unique Pointer Class. Copying and Moving Unique Pointers

CPSC 427: Object-Oriented Programming

Object Oriented Programming. Assistant Lecture Omar Al Khayat 2 nd Year

Inheritance, polymorphism, interfaces

G52CPP C++ Programming Lecture 10. Dr Jason Atkin

POLYMORPHISM 2 PART. Shared Interface. Discussions. Abstract Base Classes. Abstract Base Classes and Pure Virtual Methods EXAMPLE

Object-Oriented Design (OOD) and C++

POLYMORPHISM 2 PART Abstract Classes Static and Dynamic Casting Common Programming Errors

The mechanism that allows us to extend the definition of a class without making any physical changes to the existing class is called inheritance.

Transcription:

Object-Oriented Programming, Iouliia Skliarova

You reuse code by creating new classes, but instead of creating them from scratch, you use existing classes that someone else has built and debugged. In composition the new class is composed of objects of existing classes. Vehicle Engine Composition is often referred to as a has-a relationship, as in a car has an engine. class Engine // definition of the engine class Vehicle Engine engine; // definition of the vehicle The Vehicle class only has access to the public members of Engine.

Inheritance permits new classes to be derived from the existing classes, reusing their interface and adding new functionality. Base class (superclass) Shape Circle Rectangle Triangle Derived class (subclass) Square class Shape //definition of the class class Triangle : public Shape //definition of the class is-a relationship, because you can say a triangle is a (specific) shape.

When you inherit from an existing type, you create a new type. The new class has all the members of the old class (although the private ones are hidden away and inaccessible), and has the same interface. All the messages you can send to objects of the base class you can also send to objects of the derived class. You have two ways to differentiate your new derived class from the original base class: 1. Add brand new functions to the derived class. 2. Change the behaviour of an existing base-class function. This is referred to as overriding that function.

class X int i; X() i = 0; } void set(int ii) i = ii; } int read() const return i; } class Y : public X int i; Y() i = 0; } void set(int ii) i = ii; X::set(ii); } int main() cout << "sizeof(x) = " << sizeof(x) << endl; cout << "sizeof(y) = " << sizeof Y << endl; overriding Y D; D.read(); } D.set(12);

The constructor initializer list occurs only in the definition of the constructor and is a list of constructor calls that occur after the function argument list and a colon, but before the opening brace of the constructor body. This is to remind you that the initialization in the list occurs before any of the main constructor code is executed. When an object is created, the compiler guarantees that constructors for all of its subobjects are called.

class A A () b = CBook ( Test, 2010); } private: CBook b; int n; The constructor initializer list is empty => 1) A default CBook constructor will be called to initialize the subobject b; 2) A temporary object will be constructed with the call of CBook ( Test, 2010); 3) The operator = will assign the temporary object to b; 4) The temporary object will be destroyed. A () : b ( Test, 2010), n (10) Here, the object b is initialized with just one constructor call!

class A A () : b ( Test, 2010), n (10) private: CBook b; int n; Pseudo-constructor If you do not call the pseudo-constructor explicitly, no initialization will be done. int i (3); int* ip = new int (12);

The constructor initializer list should contain a call to the base-class constructor. class CPerson std::string m_sname; unsigned m_uage; CPerson(std::string name, unsigned age); class CStudent : public CPerson int m_imecnum; CStudent(std::string name, unsigned age, int num) : CPerson (name, age) m_imecnum = num;

Construction starts at the very root of the class hierarchy, and at each level the base class constructor is called first, followed by the member object constructors. CStudent ("Ana Lopes", 23, 12345); 1. Constructor of CPerson 2. Constructor of CStudent The destructors are called in exactly the reverse order. 1. Destructor of CStudent 2. Destructor of CPerson

Anytime you redefine an overloaded function name from the base class, all the other versions are automatically hidden in the new class. class Base int f(); int f(int flag); class Derived1 : public Base class Derived2 : public Base int f(); int main() Derived1 d1; } d1.f(); d1.f(0); Derived2 d2; d2.f(); // d2.f(0); error

Not all functions are automatically inherited from the base class into the derived class. Functions that don t automatically inherit: 1. Constructors 2. Destructors 3. Operator = If the derived class does not have any constructor, the compiler will synthesize the default constructor. The synthesized constructor will call the default constructor of the base class. If the derived class does not have the destructor, the compiler will synthesize one.

Taking the address of an object (either a pointer or a reference) and treating it as the address of the base type is called upcasting because of the way inheritance trees are drawn with the base class at the top. upcasting CPerson Example: CStudent s; CProfessor p; CPerson* ps = &s; CPerson& rp = p; CStudent CProfessor

The base class can be declared as either private, protected or public, for example: class DERIVED_PUBLIC : public BASE class DERIVED_PROTECTED : protected BASE class DERIVED_PRIVATE : private BASE When you re inheriting, the base class defaults to private. The access specifier controls: 1) access to the members of the base class; 2) pointer and reference upcasting.

In public inheritance: - public members of the base class remain public members in the derived class; - protected members of the base class remain protected members in the derived class; - private members of the base class are inaccessible in the derived class. If a class B is the public base of the class D, then public members of B can be used by anyone and protected members of B can be used by members and friends of D. Anyone can upcast D* to B*.

class c1 int pub_1; protected: int prot_1; private: int priv_1; class c2 : public c1 int pub_2; c2() pub_1; prot_1; priv_1; } protected: int prot_2; private: int priv_2; c1 a; a.pub_1; a.prot_1; a.priv_1; c2 b; b.pub_1; b.pub_2; b.prot_2; b.priv_2; c1* p = new c2;

In protected inheritance: - public members of the base class transform into protected members in the derived class; - protected members of the base class remain protected members in the derived class; - private members of the base class are inaccessible in the derived class. If a class B is the protected base of the class D, then public and protected members of B can only be used by members and friends of D. Only members of D can upcast D* to B*.

class c1 int pub_1; protected: int prot_1; private: int priv_1; class c2 : protected c1 int pub_2; c2() pub_1; prot_1; priv_1; c1* p = new c2; } protected: int prot_2; private: int priv_2; c1 a; a.pub_1; a.prot_1; a.priv_1; c2 b; b.pub_1; b.pub_2; b.prot_2; b.priv_2; c1* p = new c2;

In private inheritance: - public and protected members of the base class transform into private members in the derived class; - private members of the base class are inaccessible in the derived class. If a class B is the private base of the class D, then public and protected members of B can only be used by members and friends of D. Only members of D can upcast D* to B*.

class c1 int pub_1; protected: int prot_1; private: int priv_1; class c2 : private c1 int pub_2; c2() pub_1; prot_1; priv_1; c1* p = new c2; } protected: int prot_2; private: int priv_2; c1 a; a.pub_1; a.prot_1; a.priv_1; c2 b; b.pub_1; b.pub_2; b.prot_2; b.priv_2; c1* p = new c2;

Normally, you ll make the inheritance public so the interface of the base class is also the interface of the derived class. Public derivation means is-a for derived classes and friends. (list sorted list) When you inherit privately, you re implementing in terms of; that is, you re creating a new class that has all of the data and functionality of the base class, but that functionality is hidden, so it s only part of the underlying implementation. The class user has no access to the underlying functionality, and an object cannot be treated as a instance of the base class. (list stack) Protected derivation means implemented-in-terms-of to other classes but isa for derived classes and friends. It s something you don t use very often, but it s in the language for completeness.

class CPerson void print () const cout << I am a person!" << endl; } class CStudent : public CPerson void print () const cout << I am a student!" << endl; } I am a person!? int main (int argc, char* argv[]) CStudent s1; CPerson& r = s1; r.print(); } early return 0; Connecting a function call to a function body is called binding. (before the program is run) late (at runtime)

To cause late binding to occur for a particular function, C++ requires that you use the virtual keyword when declaring the function in the base class. Late binding occurs only with virtual functions, and only when you re using an address of the base class where those virtual functions exist. person.h class CPerson virtual void print () const; person.cpp void CPerson::print() const cout << I am a person!" << endl; If a function is declared as virtual in the base class, it is virtual in all the derived classes. The redefinition of a virtual function in a derived class is usually called overriding.

person.h class CPerson virtual void print () const; student.h class CStudent : public CPerson void print () const; person.cpp void CPerson::print() const cout << I am a person!" << endl; int main (int argc, char* argv[]) CStudent a1; CPerson& r = s1; r.print(); } return 0; student.cpp void CStudent::print() const cout << I am a student!" << endl; I am a student!

With print() defined as virtual in the base class, you can add as many new types as you want without changing the code that calls print() for objects of different types. post_gr.h class CPostGradStudent : public CStudent void print () const; int main (int argc, char* argv[]) CPostGradStudent a2; CPerson& r = a2; r.print(); return 0; } post_gr.cpp void CPostGradStudent::print() const cout << I am a postgraduate" student!" << endl; I am a postgraduate student! Such a program is extensible because you can add new functionality by inheriting new data types from the common base class. The functions that manipulate the base class interface will not need to be changed at all to accommodate the new classes.

post_gr.h post_gr.cpp class CPostGradStudent : public CStudent void CPostGradStudent::print() const void print () const; cout << " I am a postgraduate " student!" << endl; CPerson PhD_student.h class CPhDStudent : public CPostGradStudent int main (int argc, char* argv[]) CPhDStudent s3; CPerson& r = s3; r.print(); } return 0; CStudent CPostGradStudent CPhDStudent I am a postgraduate student!

The keyword virtual tells the compiler it should not perform early binding. The typical compiler creates a single table (called the VTABLE) for each class that contains virtual functions. The compiler places the addresses of the virtual functions for that particular class in the VTABLE. In each class with virtual functions, it secretly places a pointer, called the vpointer (abbreviated as VPTR), which points to the VTABLE for that object. When you make a virtual function call through a base-class pointer (that is, when you make a polymorphic call), the compiler quietly inserts code to fetch the VPTR and look up the function address in the VTABLE, thus calling the correct function and causing late binding to take place.

class NoVirtual int a; void x() } int i() return 1; } int: 4 NoVirtual: 4 void*: 4 OneVirtual: 8 TwoVirtuals: 8 class OneVirtual int a; virtual void x() } int i() return 1; } class TwoVirtuals int a; virtual void x() } virtual int i() return 1; } int main() cout << "int: " << sizeof(int) << endl; cout << "NoVirtual: " << sizeof(novirtual) << endl; cout << "void* : " << sizeof(void*) << endl; cout << "OneVirtual: " << sizeof(onevirtual) << endl; cout << "TwoVirtuals: " << sizeof(twovirtuals) << endl; } return 0;

CPerson* A [] = new CPerson, new CStudent, new CPostGradStudent, new CPhDStudent Array of pointers to persons: Objects: CPerson vptr VTABLES: &CPerson::print CStudent vptr &CStudent::print CPostGradStudent vptr &CPostGradStudent::print CPhDStudent vptr &CPostGradStudent::print

class CPerson virtual void print () const cout << I am a person!" << endl; } virtual void print_me() const; virtual ~CPerson(); class CStudent : public CPerson void print () const cout << I am a student!" << endl; } void print_me() const; ~CStudent();

pointer to a person: Object: VTABLE: CStudent vptr &CStudent :: print [0] &CStudent :: print_me [1] &CStudent :: ~CStudent [2] CStudent s; CPerson& pr = s; pr.print_me(); no virtual: call the function CPerson::print_me virtual: call the function at the address VPTR[1] mov ecx,dword ptr [ebp-14h] call @ILT+160(CPessoa::print_me) (004010a5) mov ecx,dword ptr [ebp-14h] mov edx,dword ptr [ecx] mov esi,esp mov ecx,dword ptr [ebp-14h] call dword ptr [edx+4] cmp esi,esp call chkesp (004038d0)

The vpointer is inicialized to the proper VTABLE in the constructor. Upcasting deals only with addresses. If the compiler has an object, it knows the exact type and therefore will not use late binding for any function calls. int main() CStudent s; s.print(); CPerson& pr = s; pr.print(); CPerson* pp = &s; pp.print(); static binding dynamic binding dynamic binding Overhead } return 0;

class B int* a; B() a = new int[2]; cout << "constr_b\n"; } ~B() delete[] a; cout << "destr_b\n"; } int main(int argc, char* argv[]) B* pb = new D; delete pb; return 0; } class D : public B int* b; D() b = new int[4]; cout << "constr_d\n"; } ~D() delete[] b; cout << "destr_d\n"; } The results: constr_b constr_d destr_b

a = new int[2]; memory constr_b constr_d destr_b b = new int[4]; delete[] a; Firstly, the constructor for the base class is executed, and only after that the derived class constructor is run. The destructors are executed in the reverse order. We have a problem with the destructor calls.

The problem is resolved with virtual destructors. class B int* a; B() a = new int[2]; cout << "constr_b\n"; } virtual ~B() delete[] a; cout << "destr_b\n"; } class D : public B int* b; D() b = new int[4]; cout << "constr_d\n"; } virtual ~D() delete[] b; cout << "destr_d\n"; } The results: constr_b constr_d destr_d destr_b

a = new int[2]; memory constr_b constr_d destr_d destr_b b = new int[4]; delete[] b; delete[] a; It is possible for the destructor to be virtual because the object already knows what type it is (whereas it doesn t during construction). Once an object has been constructed, its VPTR is initialized, so virtual function calls can take place. Forgetting to make a destructor virtual is an insidious bug because it often doesn t directly affect the behavior of your program, but it can quietly introduce a memory leak.

Constructors cannot be virtual. Destructors can and often must be virtual. If you re inside an ordinary member function and you call a virtual function, that function is called using the late-binding mechanism. Inside a constructor or a destructor, only the local version of the member function is called; the virtual mechanism is ignored. The reason is that you d be calling a function that might manipulate members that hadn t been initialized yet or had already been destroyed!

Bruce Eckel, Thinking in C++, 2nd edition, MindView, Inc., 2003 => Chapters 14, 15