# CSE332S Object-Oriented Programming in C++ (Lecture 12)

## Object-Oriented Programming (OOP) in C++

Today:

1. Type vs. Class
2. Subtypes and Substitution
3. Polymorphism
    a. Parametric polymorphism (generic programming)
    b. Subtyping polymorphism (OOP)
4. Inheritance and Polymorphism in C++
    a. construction/destruction order
    b. Static vs. dynamic type
    c. Dynamic binding via virtual functions
    d. Declaring interfaces via pure virtual functions

## Type vs. Class, substitution

### Type (interface) vs. Class

Each function/operator declared by an object has a signature: name, parameter list, and return value

The set of all public signatures defined by an object makes up the interface to the object, or its type

- An object’s type is known (what can we request of an object?)
- Its implementation is not - different objects may implement an interface very differently
- An object may have many types (think interfaces in Java)

An object’s class defines its implementation:

- Specifies its state (internal data and its representation)
- Implements the functions/operators it declares

### Subtyping: Liskov Substitution Principle

An interface may contain other interfaces!

A type is a **subtype** if it contains the full interface of another type (its **supertype**) as a subset of its own interface. (subtype has more methods than supertype)

**Substitutability**: if S is a subtype of T, then objects of type T may be replaced with objects of type S

Substitutability leads to **polymorphism**: a single interface may have many different implementations

## Polymorphism

Parametric (interface) polymorphism (substitution applied to generic programming)

- Design algorithms or classes using **parameterized types** rather than specific concrete data types.
- Any class that defines the full interface required of the parameterized type (is a **subtype** of the parameterized type) can be substituted in place of the type parameter **at compile-time**.
- Allows substitution of **unrelated types**.

### Polymorphism in OOP

Subtyping (inheritance) polymorphism: (substitution applied to OOP)

- A derived class can inherit an interface from its parent (base) class
  - Creates a subtype/supertype relationship. (subclass/superclass)
  - All subclasses of a superclass inherit the superclass’s interface and its implementation of that interface.
  - Function overriding - subclasses may override the superclass’s implementation of an interface
    - Allows the implementation of an interface to be substituted at run-time via dynamic binding

## Inheritance in C++ - syntax

### Forms of Inheritance in C++

A derived class can inherit from a base class in one of 3 ways:

- Public Inheritance ("is a", creates a subtype)
  - Public part of base class remains public
  - Protected part of base class remains protected
- Protected Inheritance ("contains a", **derived class is not a subtype**)
  - Public part of base class becomes protected
  - Protected part of base class remains protected
- Private Inheritance ("contains a", **derived class is not a subtype**)
  - Public part of base class becomes private
  - Protected part of base class becomes private

So public inheritance is the only way to create a **subtype**.

```cpp
class A {
public:
 int i;
protected:
 int j;
private:
 int k;
};
class B : public A {
// ...
};
class C : protected A {
// ...
};
class D : private A {
// ...
};
```

Class B uses public inheritance from A

- `i` remains public to all users of class B
- `j` remains protected. It can be used by methods in class B or its derived classes

Class C uses protected inheritance from A

- `i` becomes protected in C, so the only users of class C that can access `i` are the methods of class C
- `j` remains protected. It can be used by methods in class C or its derived classes

Class D uses private inheritance from A

- `i` and `j` become private in D, so only methods of class D can access them.

## Construction and Destruction Order of derived class objects

### Class and Member Construction Order

```cpp
class A {
public:
 A(int i) : m_i(i) {
 cout << "A" << endl;}
 ~A() {cout<<"~A"<<endl;}
private:
 int m_i;
};
class B : public A {
public:
 B(int i, int j)
 : A(i), m_j(j) {
 cout << "B" << endl;}
 ~B() {cout << "~B" << endl;}
private:
 int m_j;
};
int main (int, char *[]) {
 B b(2,3);
 return 0;
};
```

In the main function, the B constructor is called on object b

- Passes in integer values 2 and 3

B constructor calls A constructor

- passes value 2 to A constructor via base/member initialization list

A constructor initializes `m_i` with the passed value 2

- Body of A constructor runs
- Outputs "A"

B constructor initializes `m_j` with passed value 3

- Body of B constructor runs
- outputs "B"

### Class and Member Destruction Order

```cpp
class A {
public:
 A(int i) : m_i(i) {
 cout << "A" << endl;}
 ~A() {cout<<"~A"<<endl;}
private:
 int m_i;
};
class B : public A {
public:
 B(int i, int j)
 : A(i), m_j(j) {
 cout << "B" << endl;}
 ~B() {cout << "~B" << endl;}
private:
 int m_j;
};
int main (int, char *[]) {
 B b(2,3);
 return 0;
};  
```

B destructor called on object b in main

- Body of B destructor runs
- outputs "~B"

B destructor calls “destructor” of m_j

- int is a built-in type, so it’s a no-op

B destructor calls A destructor

- Body of A destructor runs
- outputs "~A"

A destructor calls “destructor” of m_i

- again a no-op

At the level of each class, order of steps is reversed in constructor vs. destructor

- ctor: base class, members, body
- dtor: body, members, base class

In short, cascading order is called when constructor is called, and reverse cascading order is called when destructor is called.

## Polymorphic function calls - function overriding

### Static vs. Dynamic type

The type of a variable is known statically (at compile time), based on its declaration

```cpp
int i; int * p;
Fish f; Mammal m;
Fish * fp = &f;
```

However, actual types of objects aliased by references & pointers to base classes vary dynamically (at run-time)

```cpp
Fish f; Mammal m;
Animal * ap = &f; // dynamic type is Fish
ap = &m; // dynamic type is Mammal
Animal & ar = get_animal(); // dynamic type is the type of the object returned by get_animal()
```

A base class and its derived classes form a set of types

`type(*ap)` $\in$ `{Animal, Fish, Mammal}`
`typeset(*fp)` $\subset$ `typeset(*ap)`

Each type set is **open**

- More subclasses can be added

### Supporting Function Overriding in C++: Virtual Functions

Static binding: A function/operator call is bound to an implementation at compile-time

Dynamic binding: A function/operator call is bound to an implementation at run-time. When dynamic binding is used:

1. Lookup the dynamic type of the object the function/operator is called on
2. Bind the call to the implementation defined in that class

Function overriding requires dynamic binding!

In C++, virtual functions facilitate dynamic binding.

```cpp
class A {
public:
 A () {cout<<" A";}
 virtual ~A () {cout<<" ~A";} // tells compiler that this destructor might be overridden in a derived class (the destructor of the parent class is usually virtual)
 virtual void f(int); // tells compiler that this function might be overridden in a derived class
};
class B : public A {
public:
 B () :A() {cout<<" B";}
 virtual ~B() {cout<<" ~B";}
 virtual void f(int) override; // tells compiler that this function might be overridden in a derived class, the parent function is virtual otherwise it will be an error
//C++11
};
int main (int, char *[]) {
 // prints "A B"
 A *ap = new B;
 // prints "~B ~A" : would only
 // print "~A" if non-virtual
 delete ap;
 return 0;
};
```

Virtual functions:

- Declared virtual in a base class
- Can override in derived classes
- Overriding only happens when signatures are the same

- Otherwise it just overloads the function or operator name

When called through a pointer or reference to a base class:

- function/operator calls are resolved dynamically

Use `final` (C++11) to prevent overriding of a virtual method

Use `override` (C++11) in derived class to ensure that the signatures match (error if not)

```cpp
class A {
public:
 void x() {cout<<"A::x";};
 virtual void y() {cout<<"A::y";};
};
class B : public A {
public:
 void x() {cout<<"B::x";};
 virtual void y() {cout<<"B::y";};
};
int main () {
 B b;
 A *ap = &b; B *bp = &b;
 b.x (); // prints "B::x": static binding always calls the x() function of the class of the object
 b.y (); // prints "B::y": static binding always calls the y() function of the class of the object
 bp->x (); // prints "B::x": lookup the type of bp, which is B, and x() is non-virtual so it is statically bound
 bp->y (); // prints "B::y": lookup the dynamic type of bp, which is B (at run-time), and call the overridden y() function
 ap->x (); // prints "A::x": lookup the type of ap, which is A, and x() is non-virtual so it is statically bound
 ap->y (); // prints "B::y": lookup the dynamic type of ap, which is B (at run-time), and call the overridden y() function of class B
 return 0;
};
```

Only matter with pointer or reference

- Calls on object itself resolved statically
- E.g., `b.y();`

Look first at pointer/reference type

- If non-virtual there, resolve statically
- E.g., `ap->x();`
- If virtual there, resolve dynamically
- E.g., `ap->y();`

Note that virtual keyword need not be repeated in derived classes

- But it’s good style to do so

Caller can force static resolution of a virtual function via scope operator

- E.g., `ap->A::y();` prints “A::y”

Potential Problem: Class Slicing

When a derived type may be caught by a catch block, passed into a function, or returned out of a function that expects a base type:

- Be sure to catch by reference
- Pass by reference
- Return by reference

Otherwise, a copy is made:

- Loses original object's "dynamic type"
- Only the base parts of the object are copied, resulting in the class slicing problem

## Class (implementation) Inheritance VS. Interface

Inheritance
Class is the implementation of a type.

- Class inheritance involves inheriting interface and implementation
  - Internal state and representation of an object

Interface is the set of operations that can be called on an object.

- Interface inheritance involves inheriting only a common interface
  - What operations can be called on an object of the type?
  - Subclasses are related by a common interface
  - But may have very different implementations

In C++, pure virtual functions make interface inheritance possible.

```cpp
class A { // the abstract base class
public:
 virtual void x() = 0; // pure virtual function, no default implementation
 virtual void y() = 0; // pure virtual function, no default implementation
};
class B : public A { // B is still an abstract class because it still has a pure virtual function y() that is not defined
public:
 virtual void x();
};
class C : public B { // C is a concrete derived class because it has all the pure virtual functions defined
public:
 virtual void y();
};
int main () {
 A * ap = new C; // ap is a pointer to an abstract class type, but it can point to a concrete derived class object, cannot create an object of an abstract class, for example, new A() will be an error.
 ap->x ();
 ap->y ();
 delete ap;
 return 0;
};
```

Pure Virtual Functions and Abstract Base Classes:

A is an **abstract (base) class**

- Similar to an interface in Java
- Declares pure virtual functions (=0)
- May also have non-virtual methods, as well as virtual methods that are not pure virtual

Derived classes override pure virtual methods

- B overrides `x()`, C overrides `y()`

Can't instantiate an abstract class

- class that declares pure virtual functions
- or inherits ones that are not overridden

A and B are abstract, can create a C

Can still have a pointer or reference to an abstract class type

- Useful for polymorphism

## Review of Inheritance and Subtyping Polymorphism in C++

Create related subclasses via public inheritance from a common superclass

- All subclasses inherit the interface and its implementation from the superclass

Override superclass implementation via function overriding

- Relies on virtual functions to support dynamic binding of function/operator calls

Use pure virtual functions to declare a common interface that related subclasses can implement

- Client code uses the common interface, does not care how the interface is defined. Reduces complexity and dependencies between objects in a system.
