CS 112 - Week 14 Lecture 2 - 2022-12-01

TODAY WE WILL:
*   announcements
*   quick note about divide-by-zero
*   adding OVERRIDING to overloading and redefining
*   discussion of multiple inheritance
*   prep for next class

*   weird fun fact: evidentally divide by zero is NOT
    defined as a C++ exception!
    ... instead it is a CPU signal that the OS sends to
        your program signal handler routine that,
	by default, terminates the program...!

====
another term! OVERRIDING, to join overloading and redefining
====
*   (this is also in Savitch Ch. 15)

*   redefining: for a non-virtual method, you are
    making an alternate version of an inherited method
    to essentially replace the inherited version

    (has the same signature -- same number and types of
    arguments, same return type)

*   overloading: for a non-virtual method(?), you are adding
    and *additional* version of that method, with different
    number and/or type of arguments;

*   WHEN a method IS a virtual method,
    programmers often say a derived class' version of
    an inherited method intended to replace the inherited
    method is OVERRIDING the inherited version,
    instead of redefining it.

    ...rather a subtle distinction!

    Savitch suggest maybe this terminology is here because
    the compiler DOES treat an overridden method different
    than a redefined method... (the virtual overridden
    method DOES have the possibility of dynamic binding)

=====
a few words on MULTIPLE inheritance!
=====
*   what do we mean by this?
    ...we mean a derived class can have MORE than
       one base class

    (this is distinct from a class having, say,
    ancestor classes...

    Dessert -> Pie -> CustardPie		is not multiple
                                                inheritance

        ParentA    ParentB
	   ^           ^
            \         /

             DerivedC

THIS is multiple
inheritance --
DerivedC has TWO base classes, ParentA and ParentB

*   the syntax is simple:

    class DerivedC: public ParentA, public ParentB

    (some of the implications and complications are not
    simple, but the syntax is...!)

*   attempt at some examples where this be useful:

    class Mammal
    ...

    class WingedAnimal
    ...

    class Bat: public Mammal, public WingedAnimal
    ...

    =====

    class Scanner
    ...

    class Printer
    ...

    class Copier: public Scanner, public Printer
    ...

====
a few details related to multiple inheritance
====
*   the constructors of a derived class derived from
    multiple base classes are called in the same
    order in which they are inheritedx
    (in which they appear in the class definition header)

    class Bat: public Mammal, public WingedAnimal

    ... constructor for Mammal will be called,
        then constructor for WingedAnimal will be called

    *   the destructors are called in REVERSE order
        of the constructors
        (so, first WingedAnimal's destructor,
	     then Mammal's destructor)

=====
ISSUES with multiple inheritance
=====
*   so if both parents have a common public method,
    you'll get a compiler error if you just call
    that method for the derived class --

    it will complain about AMBIGUITY!!

    *   you can get around that by explicitly specifying
        which parent's you wish to call,
	for each call!

	DesiredParent::common_method_name

*   a bigger classic problem:
    the diamond problem

    *   can occur when you have a derived class
        with multiple parents, but some of those
	parents are themselves derived classes of
	a common base class

    class Person
    ....

    class Student: public Person
    ....

    class Faculty: public Person
    ....

    class TA: public Student, public Faculty
    ....

==== WHAT IF, as another example:

    class PoweredDevice
    ...
   
    class Scanner: public PoweredDevice
    ...

    class Printer: public PoweredDevice
    ...

    class Copier: public Scanner, public Printer
    ...

*   yikes -- a TA object would try to call
    the Person constructor twice! -- two copies of all members
    of Person;

    and when that TA passes out of scope, Person's destructor
    would end up being called twice;

*   SOLUTION? a slightly different use of the
    virtual keyword!

    You can declare a class as a VIRTUAL base class
    for another class by putting virtual before public
    for that class:

    class Faculty: virtual public Person
    ...

    // Faculty now has Person as a virtual base class.

    class Student: virtual public Person
    ...

    // Student now has Person as a virtual base class.

=====
abstract class
=====
*   a class in C++ is an ABSTRACT class if it has
    at least one PURE virtual method

    *   what's a pure virtual method?

        a pure virtual method has NO implementation.

    *   If a derived class is derived from an abstract base class,
        it EITHER must implement every pure virtual method
	OR it will also be an abstract class

    *   FUN FACT: a abstract class cannot be instantiated
        (you can't create an instance of it). BUT it can
	be used as a base class.

*   SYNTAX for a pure virtual method:
    in the class DECLARATION (in our case, the .h file)

    virtual ret_type method_name(param_decls) = 0;

    virtual double get_perimeter() = 0;

*   why would we want abstract classes?

    They are meant to represent general concepts
    (for example, Shape or Animal etc.) for which
    you don't want instances, but you WOULD like to
    use as base classes for more-concrete derived
    classes you do want instances of (for example, Circle or Dog, etc.)

*   what about a PURE ABSTRACT class?
    *   A pure abstract class has ONLY abstract methods
        and NO data fields and NO concrete methods

    *   In general, a pure abstract class is used to
        define an interface and is intended to be inherited
	by concrete classes.

        It's a way of forcing a kind of contract between
	the class designer and users of that class