2 1 C Interface struct Int List typedef

  • Slides: 90
Download presentation
2 1

2 1

C Interface struct Int. List; typedef struct Int. List; Int. List* int. List. New();

C Interface struct Int. List; typedef struct Int. List; Int. List* int. List. New(); void int. List. Free( Int. List* List ); void int. List. Push. Front( Int. List* List, int x); void int. List. Push. Back( Int. List* List, int x); int. List. Pop. Front( Int. List* List ); int. List. Pop. Back( Int. List* List ); int. List. Is. Empty( Int. List const* List); typedef void (*func. Int)( int x, void* Data ); void int. List. MAPCAR( Int. List* List, func. Int Func, void* Data ); 2

C++ Class In header file: private: class Int. List struct Node { { public:

C++ Class In header file: private: class Int. List struct Node { { public: int value; Int. List(); Node *next; ~Int. List(); void push. Front(int x); Node *prev; void push. Back(int x); }; Node* m_start; int pop. Front(); Node* m_end; int pop. Back(); bool is. Empty() const; }; 3

Classes & Memory allocation Consider this C++ code main() { Int. List L; }

Classes & Memory allocation Consider this C++ code main() { Int. List L; } What is the difference? 4 Compare to C style: main() { Int. List* L = (Int. List*)malloc (sizeof(Int. List)); free(L) }

Classes & Memory allocation Int. List* L = (Int. List*)malloc(sizeof(Int. List)); Does not call

Classes & Memory allocation Int. List* L = (Int. List*)malloc(sizeof(Int. List)); Does not call constructor! Internal data members are not initialized free(L); Does not call destructor! Internal data members are not freed 5

new & delete Special operators: Int. List *L = new Int. List; 1. Allocate

new & delete Special operators: Int. List *L = new Int. List; 1. Allocate memory 2. Call constructor 3. Return pointer to the constructed object delete L; 1. Call destructor 2. Free memory 6

new Can be used with any type: int *i = new int; char **p

new Can be used with any type: int *i = new int; char **p = new (char *); • new is a global operator • new expression invokes the new operator to allocate memory, and then calls ctor • Can be overloaded (or replaced) • By default, failure throws exception. Can be changed. • See <new> header 7

Global operator new (simplified) void *operator new(size_t size) { void *p; if((p = malloc(size))

Global operator new (simplified) void *operator new(size_t size) { void *p; if((p = malloc(size)) == 0) { throw std: : bad_alloc; } return p; } 8

New & Constructors class My. Class { public: 1 My. Class(); 2 My. Class(

New & Constructors class My. Class { public: 1 My. Class(); 2 My. Class( int i ); 3 My. Class( double x, double y ); }; 9 My. Class* a; a = new My. Class; // Calls 1 a = new My. Class(5); // Calls 2 a = new My. Class( 1. 0, 0. 0 ); // Calls 3

New & arrays To allocate arrays, use int n = 4; int *a =

New & arrays To allocate arrays, use int n = 4; int *a = new int[10]; // array of 10 //ints Int. List *b = new Int. List[n]; // array of n Int. Lists 10 Objects in allocated array must have an argument-less constructor!

Allocate array of objects w/o def. cons. int n = 4; My. Class **arr

Allocate array of objects w/o def. cons. int n = 4; My. Class **arr = new My. Class *[n]; // array of n pointers to My. Class (no // cons. is invoked) for (int i=0; i<n; i++) { arr[i] = new My. Class (i); // each pointer points to a My. Class // object allocated on the heap, and // the cons. is invoked. } 11

Delete & array Special operation to delete arrays int *a = new int[10]; int

Delete & array Special operation to delete arrays int *a = new int[10]; int *b = new int[10]; delete [] a; // proper delete command delete b; // may work, but may // cause memory leak! 12

Free an allocated array of pointers to objects on the heap int n =

Free an allocated array of pointers to objects on the heap int n = 4; for (int i=0; i<n; i++) { delete (arr[i]); // invoked the dest. of each My. Class // object allocated on the heap, and // free the memory. } delete [] arr; // free the memory allocated for the // array of pointers. No dest. is invoked 13

Initialization List

Initialization List

The default ctor int main() { B b; class A { public: A() {

The default ctor int main() { B b; class A { public: A() { std: : cout << "A - default ctorn"; } }; 15 class B { A _a 1, _a 2; public: B() { std: : cout << "B default ctorn"; } }; // output A – default ctor B - default ctor

Class with object members int main() { B b; 16 class B { A

Class with object members int main() { B b; 16 class B { A _a 1, _a 2; public: B() { std: : cout << "B default ctorn"; } }; class A { public: A(int a) { std: : cout << "A ctor with one parametern"; } }; // compilation error No default ctor for _a 1, _a 2

The initialization list int main() { B b (2, 3); class A { public:

The initialization list int main() { B b (2, 3); class A { public: A(int a) { std: : cout << "A (" << a << ") " << std: : endl; } }; 17 class B { A _a 1, _a 2; public: B(int i, int j) : _a 1 (i), _a 2(j) { std: : cout << "B cons" << std: : endl; } // output A (2) }; A (3) B cons

Initialization using pointers (1) int main() { B b (2); class A { public:

Initialization using pointers (1) int main() { B b (2); class A { public: A(int a); }; A: : A(int a) { std: : cout << "A (" 18 << a << ")" << endl; } class B { A *_a 1; public: B(int i); }; B: : B(int i) { _a 1 = new A (i); cout << "B consn"; } // output A (2) B cons

Initialization using pointers (2) int main() { B b (2); class A { public:

Initialization using pointers (2) int main() { B b (2); class A { public: A(int a); }; A: : A(int a) { std: : cout << "A (" 19 << a << ")" << endl; } class B { A *_a 1; public: B(int i); }; B: : B(int i): _a 1 (new A (i)) { cout << "B consn"; } // output A (2) B cons

The initialization list 1. Initialization of object members. 2. Initialization of constants and reference

The initialization list 1. Initialization of object members. 2. Initialization of constants and reference variables. 3. In the future: Initialization of parent class. 4. It is faster and safer to use the initialization list than initialization in the constructor 20

Reference variables

Reference variables

References • A reference is an alias – an alternative name to an existing

References • A reference is an alias – an alternative name to an existing object int i = 10; int& j = i; // j is a int reference // initialized only // once ! j += 5; // changes both i and j int* k = new int(); j = k; //error j = *k; //ok 22

The famous swap again // C version void swap (int *a, int *b) {

The famous swap again // C version void swap (int *a, int *b) { int t = *a; *a = *b; *b = t; } // C++ version void swap (int &a, int &b) { int t = a; a = b; b = t; } • More intuitive syntax • No pointer arithmetic mistakes • Ref variables are actually const pointers (standard implementation) • Must be initialized in their declaration (initialization list), like const variables 23

Pointer vs non-const reference References can be used as output parameters, similar to pointers.

Pointer vs non-const reference References can be used as output parameters, similar to pointers. Pros: • It is hard to have reference to undefined value. • The syntax inside the function is clearer But: • You can’t see what you are doing at call site. • As a convention always order argument, in first out last. 24

Lvalue & Rvalue int a=1; a=5; // Lvalue = Rvalue, Ok a=a; // Lvalue

Lvalue & Rvalue int a=1; a=5; // Lvalue = Rvalue, Ok a=a; // Lvalue = Lvalue, Ok 5=a; // Rvalue = Lvalue Comp. error 5=5; // Rvalue = Rvalue Comp. error Lvalues: variables, references … Rvalues: numbers, temporaries … Temporary: A result of expression that isn't stored – a+5 creates a temporary int with value 6. 25

R/L value and references non-const Reference – only to a non const Lvalue. const

R/L value and references non-const Reference – only to a non const Lvalue. const reference – to both Lvalue and Rvalue int lv=1; const int clv=2; int& lvr 1=lv; int& lvr 2=lv+1; //error! int& lvr 3=clv; //error! const int& cr 1=clv; const int& cr 2=5+5; 26

Lvalue & Rvalue int a=1; a=5; // Lvalue = Rvalue, Ok a=a; // Lvalue

Lvalue & Rvalue int a=1; a=5; // Lvalue = Rvalue, Ok a=a; // Lvalue = Lvalue, Ok 5=a; // Rvalue = Lvalue Comp. error Reference – only to Lvalue 5=5; // Rvalue = Rvalue Comp. error Const Reference – to Lvalue & Rvalue Lvalues: varibales, refernces (non const!) … C++11: Rvalues: const variables numbers, Rvaluerefernces, reference temporaries … Temporary: A result of expression that isn't stored – a+5 creates a temporary int with value 6. 27

A fancy way to pass arguments to function // Pass by value void foo

A fancy way to pass arguments to function // Pass by value void foo (int a) { . . . } // Pass by pointer void foo (int *pa) { . . . } // pass by const ref void foo (const int &a) { . . . } • Avoid from copying objects, without allowing changes in their value. 28

Return a reference to variable class Buffer { int _length; int *_buf; public: Buffer

Return a reference to variable class Buffer { int _length; int *_buf; public: Buffer (int l) : _length (l), _buf (new int [l]) { } int& get(int i) { return _buf[i]; } }; 29 int main () { Buffer buf (5); buf. get (0) = 3; } Return a ref. to a legal variable (e. g. not on the function stack).

C++ const

C++ const

Const variables – like in c int * const p 1 = &i; //

Const variables – like in c int * const p 1 = &i; // a const // pointer to an un-const variable • p 1++; // c. error • (*p 1)++; // ok const int * p 2 = &b; // an un-const // pointer to a const variable • p 2++; // ok • (*p 2)++; // c. error const int * const p 3 = &b; // a const // pointer to a const variable 32

Const objects & functions (1) class A { int main() public: { void foo

Const objects & functions (1) class A { int main() public: { void foo 1() const; A a; void foo 2(); const A ca; }; void A: : foo 1() const a. foo 1(); { a. foo 2(); } ca. foo 1(); void A: : foo 2() ca. foo 2(); // comp. { // error } } 33

Const objects & functions (2) class A { public: void foo() const; void foo();

Const objects & functions (2) class A { public: void foo() const; void foo(); }; void A: : foo() const { cout << "const foon"; } void A: : foo() { cout << "foon"; } 34 int main() { A a; const A ca; a. foo (); ca. foo(); } // output foo const foo

Why? Overload resolution, again: A: : foo(A* this) A: : foo(const A* this) 35

Why? Overload resolution, again: A: : foo(A* this) A: : foo(const A* this) 35

Return a const ref. to variable class Buffer { int main () int _length;

Return a const ref. to variable class Buffer { int main () int _length; { int *_buf; Buffer buf(5); public: buf. get(0) Buffer (int l): = 3; // illegal _length (l), std: : cout << _buf (new int [l]) { buf. get(0); } } const int& get(int i) const { return _buf[i]; Why? } }; 36

Const objects with pointers – like in c class B { public: int _n;

Const objects with pointers – like in c class B { public: int _n; }; class A { public: B* _p; A(); void foo() const; }; A: : A() : _p(new B) { _p->_n = 17; } void A: : foo() const 37 { //_p++; // this will not // compile _p->_n++; // this will ! } int main() { const A a; std: : cout << a. _p->_n << std: : endl; a. foo(); std: : cout << a. _p->_n << std: : endl; } // output 17 18

Const objects with references class A { public: int & _i; A(); void foo()

Const objects with references class A { public: int & _i; A(); void foo() const; }; A: : A(int &i) : _i(i) { } void A: : foo() const { _i++; } 38 int main() { int i = 5; const A a (i); std: : cout << a. _i << std: : endl; a. foo(); std: : cout << a. _i << std: : endl; } // output 5 6

Initialization of const and ref. 39 class A { int& _a; const int _b;

Initialization of const and ref. 39 class A { int& _a; const int _b; public: A(int a); }; A: : A(int a) { _a = a; _b = 5; } // compilation error Const and ref vars must initialized in their declaration class A { int& _a; const int _b; public: A(int a); }; A: : A(int a) : _a (a), _b (5) { }

Inheritance

Inheritance

Inheritance • The main ideas are similar to what you already know from Java.

Inheritance • The main ideas are similar to what you already know from Java. • C++ has no interfaces but it allows multiple inheritance • For now we will not discuss the problems that arise: Class A Class B Class C Class D 41

Person class Person { private: string _name; int _id; static const int NO_ID_VAL; public:

Person class Person { private: string _name; int _id; static const int NO_ID_VAL; public: Person (); Person (string name, int id); void output. Details(ostream& os) const; void change. Name(string name); void change. Id(int id); string get. Name() const; int get. Id() const; } ; 42

protected Class members that should be accessible by subclasses are declared protected. Example: to

protected Class members that should be accessible by subclasses are declared protected. Example: to allow Programmer access members of Person we would define: class Person { public: //. . . protected: //. . . }; 43

Person class Person { protected: string _name; int _id; static const int NO_ID_VAL; public:

Person class Person { protected: string _name; int _id; static const int NO_ID_VAL; public: Person (); Person (string name, int id); void output. Details(ostream& os) const; void change. Name(string name); void change. Id(int id); string get. Name() const; int get. Id() const; } ; 44

Programmer class #include "Person. h" class Programmer : public Person { char* _company; public:

Programmer class #include "Person. h" class Programmer : public Person { char* _company; public: Programmer(char* name = "", int id = 0, char* company = ""); void change. Company(char* company); char* get. Company() const; void output. Details(ostream& os=std: : cout) const; }; 45

Default parameters #include "Person. h" class Programmer : public Person { char* _company; public:

Default parameters #include "Person. h" class Programmer : public Person { char* _company; public: Programmer(char* name = "", int id = 0, char* company = ""); void change. Company(char* company); char* get. Company() const; void output. Details(ostream& os=std: : cout) const; }; Note that now Programmer has a default constructor! 46

Programmer class implementation #include "Programmer. h" Programmer: : Programmer (char* name, int id, char*

Programmer class implementation #include "Programmer. h" Programmer: : Programmer (char* name, int id, char* company) : Person(name, id), _company(company) { // EMPTY } 47

Types of inheritance A base class also has an access modifier: class Programmer :

Types of inheritance A base class also has an access modifier: class Programmer : public Person class Programmer : private Person class Programmer : protected Person private/protected inherence: • Everything declared in Person is private/protected when used from Programmer • Inside programmer you can access Person members according to Person’s modifiers • Users of programmer won't have access to Person members 48

private/protected are in class level and not in instance level class A { private:

private/protected are in class level and not in instance level class A { private: int _i; public: A(int i) : _i(i) { } void set. Ifrom. A(A a) { _i = a. _i; } }; 49 int main () { A a(5); A b(2); b. set. Ifrom. A(a); }

But: new is a global operator class A { protected: int _i; A ()

But: new is a global operator class A { protected: int _i; A () : _i(0) { } ~A () { } }; class B: public A { public: A *_pa; B() : A(), _pa(new A()) { } 50 ~B () { delete _pa; } }; int main () { A a; //ERROR B b; //ERROR }

C-tor & D-tor order of execution 1. Constructor of the base class is executed

C-tor & D-tor order of execution 1. Constructor of the base class is executed 2. Members are constructed. 3. Constructor of the class itself is executed. Destruction is done in the opposite order. 51

Overridden functions (1) void Person: : output. Details(ostream& os) const { os << "{";

Overridden functions (1) void Person: : output. Details(ostream& os) const { os << "{"; if(_name != "") os<< " name: " << _name; if(_id != NO_ID_VAL) os << ", I. D: " << _id ; os << '}'; } void Programmer: : output. Details(ostream& os) const { os << '{' << _name << ', ' << _id << ', ' << _company << '}'; } 52

Overridden functions (1) void Person: : output. Details(ostream& os) const { os << "{";

Overridden functions (1) void Person: : output. Details(ostream& os) const { os << "{"; if(_name != "") os<< " name: " << _name; if(_id != NO_ID_VAL) os << ", I. D: " << _id ; os << '}'; } void Programmer: : output. Details(ostream& os) const { Person: : output. Details(os); os <<'-' << _company << '}'; } 53

Virtual Classes & Polymorphism

Virtual Classes & Polymorphism

Example (revisited) • We want to implement a graphics system • We plan to

Example (revisited) • We want to implement a graphics system • We plan to have lists of shape. Each shape should be able to draw it self, compute its size, etc. 55

Solution #1 class Shape { public: enum Type { Square, Circle, Triangle }; Shape(

Solution #1 class Shape { public: enum Type { Square, Circle, Triangle }; Shape( Type t, Point Center, double width, double height); void Draw(); double Area(); private: Type _type; Point _center; }; 56

Solution #1 This solution gives a nice “wrapping” to the solution we consider in

Solution #1 This solution gives a nice “wrapping” to the solution we consider in C It does not solve the problems of that solution �Lack of extendibility 57

Solution #2 – different classes class Square { public: void Draw(); double Area(); };

Solution #2 – different classes class Square { public: void Draw(); double Area(); }; 58 class Circle { public: void Draw(); double Area(); };

Solution #2 – Discussion �Each shape has its own implementation �We can easily add

Solution #2 – Discussion �Each shape has its own implementation �We can easily add new shapes However, �Shapes are different types �One cannot view them as part of the same class - we cannot share code between them 59

Solution #3 - hierarchy class Shape { public: void Draw(){cout<<'h'; } double Area(); };

Solution #3 - hierarchy class Shape { public: void Draw(){cout<<'h'; } double Area(); }; class Square: public Shape { public: void Draw(); {cout<<'q'; } double Area(); }; 60 class Circle: public Shape { public: void Draw(); {cout<<'c'; } double Area(); };

Solution #3 Now we can write code such as: Shape* My. Shapes[2]; My. Shapes[0]

Solution #3 Now we can write code such as: Shape* My. Shapes[2]; My. Shapes[0] = new Circle(); My. Shapes[1] = new Square(); What will happen when we call My. Shapes[0]->Draw(); ? h will be printed! 61

Why? When we write: Circle circle; circle. Draw(); The compiler calls Circle: : Draw()

Why? When we write: Circle circle; circle. Draw(); The compiler calls Circle: : Draw() When we write: Shape* p = new circle(); p->Draw(); The compiler calls Shape: : Draw() Why? *p has type Shape 62

Class Hierarchy class Base { public: void foo(); void bar(); }; class Derived: public

Class Hierarchy class Base { public: void foo(); void bar(); }; class Derived: public Base { public: void bar(); }; 63 Derived obj; obj. foo(); Calls Base: : foo() Derived does not implement this method obj. bar(); Calls Derived: : bar() Two implementations, the more specific is used

Inheritance & Overloading Derived inherits the method foo() from Base �The inherited class uses

Inheritance & Overloading Derived inherits the method foo() from Base �The inherited class uses methods of the base class Derived overrides the implementation of bar() �This mechanism allows an inherited class to specialize the implementation 64

Static resolution How does the compiler determine which method to call? Static Resolution: Based

Static resolution How does the compiler determine which method to call? Static Resolution: Based on the type of the variable. �Not the type of the object! The compiler finds the most specific implementation of the method, and calls it 65

Static resolution in our example Circle* circle = new Circle(1, 1, 2); Square* square

Static resolution in our example Circle* circle = new Circle(1, 1, 2); Square* square = new Square(2, 2, 1); Shape* My. Shapes[2]; My. Shapes[0] = circle; My. Shapes[1] = square; circle->Draw(); // Calls Circle: : Draw() square->Draw(); // Calls Square: : Draw() My. Shapes[0]->Draw(); // Calls Shape: : Draw() My. Shapes[1]->Draw(); // Calls Shape: : Draw() 66

Dynamic Resolution This clearly not what we want to in this example. More desirable

Dynamic Resolution This clearly not what we want to in this example. More desirable here is – Dynamic resolution: • Based on the type of the object • Determined at run time [Java Like] 67

Dynamic Resolution in C++ The virtual keyword states that the method can be overridden

Dynamic Resolution in C++ The virtual keyword states that the method can be overridden in a dynamic manner. class Base { public: virtual void bar(); } class Derived: public Base { public: virtual void bar(); } 68

Solution #4: dynamic resolution Returning to the shapes example, using virtual methods gives the

Solution #4: dynamic resolution Returning to the shapes example, using virtual methods gives the desired result 69

Solution #3 - hierarchy class Shape { public: virtual void Draw() {cout<<'h'; } virtual

Solution #3 - hierarchy class Shape { public: virtual void Draw() {cout<<'h'; } virtual double Area(); }; class Square: public Shape { public: virtual void Draw(); {cout<<'q'; } virtual double Area(); }; 70 class Circle: public Shape { public: virtual void Draw(); {cout<<'c'; } virtual double Area(); };

Solution #4: dynamic resolution Returning to the shapes example, using virtual methods gives the

Solution #4: dynamic resolution Returning to the shapes example, using virtual methods gives the desired result: Shape* s=new Circle; s->Draw(); Will print 'c' 71

Virtual Methods Class Base defines a virtual method foo() The resolution of foo() is

Virtual Methods Class Base defines a virtual method foo() The resolution of foo() is dynamic in all subclasses of Base �If the subclass Derived overrides foo(), then Derived: : foo() is called �If not, Base: : foo() is called 72

Underneath the Hood: Inheritance class Base { double _x; int _a; }; class Derived

Underneath the Hood: Inheritance class Base { double _x; int _a; }; class Derived : public Base { double _z; }; Base a; Derived b; a: _x _a b: _x _a _z 73 Base

Pointing to an Inherited Class Derived b; Base* p = &b; p: When using

Pointing to an Inherited Class Derived b; Base* p = &b; p: When using *p, we treat b as though it was a Base object The compiler cannot know if *p is from a derived class or not. 74 b: _x _a _z

And with references struct B { virtual void f() { cout << "B" <<

And with references struct B { virtual void f() { cout << "B" << endl; } }; struct D : public B { void f() { cout << "D" << endl; } }; 75 int main() { D d 1; B b 1=d 1; b 1. f(); D d 2; B& b 2=d 2; b 2. f(); } //B //D

Implementation of Virtual Methods Possible approach: �If foo() is a virtual method, then each

Implementation of Virtual Methods Possible approach: �If foo() is a virtual method, then each object has a pointer to the implementation of foo() that it uses �Essentially the solution we used in our C implementation Cost: �Each virtual method requires a pointer �Large number of virtual methods � waste of memory 76

Implementation of Virtual Methods Alternative solution: �Each object has a pointer to an array

Implementation of Virtual Methods Alternative solution: �Each object has a pointer to an array of function pointer �This array points to the appropriate functions Cost: �For each class, we store one table �Each object contains one field that points to the right table 77

Example class A { public: virtual void f 1(); virtual void f 2(); int

Example class A { public: virtual void f 1(); virtual void f 2(); int _a; }; class B: public A { public: virtual void f 1(); virtual void f 3(); void f 4(); int _b; }; A a 1, a 2; B b; 78 void A: : f 1 { //. . . }; a 1: <vtbl> _a b: <vtbl> _a _b VTBLs A void A: : f 2 { //. . . }; f 1 f 2 B f 1 f 2 f 3 void B: : f 1 { //. . . }; void B: : f 3 { //. . . };

Virtual - Recap �Virtual controls whether to use static or dynamic resolution �Once a

Virtual - Recap �Virtual controls whether to use static or dynamic resolution �Once a method is virtual, it must remain so throughout the hierarchy �Calling a virtual method is more expensive than standard calls �Two pointers are “chased” to get to the address of the function 79

Destructors & Inheritance class Base { public: ~Base(); }; class Derived : public Base

Destructors & Inheritance class Base { public: ~Base(); }; class Derived : public Base { public: ~Derived(); }; Base *p = new Derived; delete p; Which destructor is called? (Base: : ~Base()) 80

Virtual Destructor • Destructor is like any other method • The example uses static

Virtual Destructor • Destructor is like any other method • The example uses static resolution, and hence the wrong destructor is called • To fix that, we need to declare virtual destructor at the base class! Once you declare virtual destructor, derived class must declare a destructor 81

Polymorphism & Inheritance • C++ allows to use class hierarchy to implement polymorphic code

Polymorphism & Inheritance • C++ allows to use class hierarchy to implement polymorphic code Points of care: • Choice of virtual methods �Run time considerations • Use of virtual destructor for base class 82

Shapes & Sizes Revisiting our example, we write: class Shape { public: virtual ~Shape();

Shapes & Sizes Revisiting our example, we write: class Shape { public: virtual ~Shape(); // Virtual destructor virtual void Draw(); // Virtual method virtual double Area(); // Also }; 83 How do we implement Shape: : Draw() ?

Inheritance & Interfaces • In this example, we never want to deal with objects

Inheritance & Interfaces • In this example, we never want to deal with objects of type Shape �Shape serves the role of an interface • All shapes need to be specific shapes that are instances of derived classes of Shape • How do we enforce this? Simple mechanism: void Shape: : Draw() { assert(false); // we should never //call this method } 84

Pure Virtual Classes We can specify that Shape: : Draw() does not exist class

Pure Virtual Classes We can specify that Shape: : Draw() does not exist class Shape { public: virtual ~Shape(); //Virtual destructor virtual void Draw() =0; // pure virtual double Area() =0; //Also }; 85

Pure Virtual We cannot create objects of a Pure Virtual class Shape* p; //

Pure Virtual We cannot create objects of a Pure Virtual class Shape* p; // legal Shape s; // illegal Circle c; // legal p = &c; // legal p = new Shape; // illegal 86

Virtual Methods - Tips 1. If you have virtual methods in a class, always

Virtual Methods - Tips 1. If you have virtual methods in a class, always declare 2. 3. 4. 5. 87 its destructor virtual Never call virtual methods during construction and destruction Use virtual methods Duplicate() and Create() for implementing “virtual constructors” – "factory" Use pure virtual classes to define interfaces Use inheritance with care: Be sure that this is the appropriate solution ("is a" relation)

Interfaces • To create an equivalent to java interface – declare a base class

Interfaces • To create an equivalent to java interface – declare a base class with all methods virtual • Inheritance can be used to hide implementation. But, you will need a factory, and later on with templates also p_impl pattern: Example on next slide: 88

C++ Class In list. h file: In list. cpp file: class List: public IList

C++ Class In list. h file: In list. cpp file: class List: public IList class IList { { public: virtual ~IList(){}; virtual void Add()=0; void Add() { virtual ~IList(){}; cout << "Add"; static Ilist* } List. Factory(); }; IList* In main. cpp: IList: : List. Factory() { IList* L = return new List; IList: : List. Factory(); } 89

Method hiding struct B { (virtual) void f(bool i) {cout << "bool" << endl;

Method hiding struct B { (virtual) void f(bool i) {cout << "bool" << endl; } }; struct D : public B { void f(int b) {cout << "int" << endl; } }; int main(){ D d; d. f(true); d. B: : f(true); } 90 d. f(3); d. B: : f(3);

Remember overloading? Inheritance in c++ is actually a use of overloading. class A: public

Remember overloading? Inheritance in c++ is actually a use of overloading. class A: public B Puts B’s declaration inside the scope of A. That’s all (almost) Remember for later… 91