Classes and Inheritance - PowerPoint PPT Presentation

1 / 39
About This Presentation
Title:

Classes and Inheritance

Description:

class Derived : public Base1, Base2 { Derived d; d.doit(); // what ... d.Base1::doit(); d.Base2::doit(); More Ambiguities and Virtual Inheritance. class Counter ... – PowerPoint PPT presentation

Number of Views:20
Avg rating:3.0/5.0
Slides: 40
Provided by: craigm6
Category:

less

Transcript and Presenter's Notes

Title: Classes and Inheritance


1
Classes and Inheritance
2
Recall Structs
  • Many programming languages support user-defined
    types that are aggregations of other objects.
  • supported in C with the struct construct
  • supported in C with the class construct
  • The aggregation allows several variables to be
    treated as a unit
  • allocated together
  • passed as parameters/return values together.

3
Implementation of Structs
  • Compiler determines a size of the aggregate
    object.
  • size of the field
  • some adjustments for address alignment
  • Compiler determines an offset for each field.
  • The . operator is implemented simply by adding
    the offset of the named field to the address of
    the aggregate.

4
Type Rules in C
  • Structs in C are legitimate types and can be
    use exactly like any base types.
  • can be parameters, global/local variables or
    return types
  • can be fields in other structs
  • derived types (pointer reference) can be based on
    structs.
  • Struct assignment is permitted in C. The
    default behavior is to use the default
    assignment/copy rules for each individual field.
  • Custom behavior can be defined using operator()
  • Strong/static type checking is used.

5
Member Functions
  • The next step up on the evolutionary ladder above
    structs is ADTs.
  • An Abstract Data Type is a software module
    consisting of a struct (data layout) plus a set
    of functions for operating on that struct.
  • These functions (obviously) require that one of
    their parameters be a pointer or reference to the
    struct that they are to manipulate.
  • Member functions support ADTs by
  • merging the source code for the data layout and
    function declarations.
  • passing the struct pointer implicitly to member
    functions

6
C and this
  • The this pointer is a parameter. For a member
    function in class T, the
  • declared T const this
  • The this pointer is passed implicitly (does not
    appear in the parameter list).
  • The implicit this pointer is the only
    implementation difference between a member
    function and a regular function!
  • The only other differences relate to
    type-checking rules (scoping and access control).

7
Pop Quiz
  • int x 0
  • class A
  • void doit(void) x 1 doit()
  • // no data members
  • class B
  • double a,b,c // 24 bytes of data members
  • void doit(void) x 1 doit()
  • Does either function run indefinitely? Which
    program runs longer (increments x more times)
    before crashing? Adoit() or Bdoit()?

8
Inheritance
  • The terminology of object-oriented programming is
    somewhat ambiguous (at least in conventional
    usage).
  • The C inheritance mechanism does at least two
    very distinct things.
  • Allows a new type to be defined as an extension
    of an existing type.
  • Creates a subtype/supertype relationship.
  • Ill refer to 1 as inheritance and as 2 as
    subtyping.

9
Inheritance for Reuse
  • Remember that the goal for object-oriented
    programming was to achieve greater/more flexible
    code reuse.
  • Imagine we have a class that provides some useful
    function, but that we wish to improve, e.g.,
    adding range checking to the standard vector
    container.

10
Defining an Inheritance Relationship
  • class Derived public Base
  • // changes from Base class
  • Public inheritance makes all of Bases public
    members available to users of Derived (public in
    base becomes public in Derived).
  • The body of Derived describes changes from Base
  • Except as explicitly changed, all of Base is
    inherited into Derived.

11
Restrictions and caveats on Inheritance
  • Constructors cannot be inherited. Must use ugly
    syntax for constructors.
  • DerivedDerived(derived_args)
  • Base(base_args)
  • Assignment operator (and other operators) are
    inherited. Can lead to some confusion with
    return types. More on this in later examples.
  • Destructor is not inherited.
  • Base constructor is invoked FIRST, base
    destructor is invoked LAST.

12
Checked Vector Example
  • template lttypename Tgt
  • class CheckedVector public vectorltTgt
  • public
  • explicit CheckedVector(int sz 0)
  • vectorltTgt(sz)
  • CheckedVector(const CheckedVectorltTgt other)
  • vectorltTgt(other)
  • CheckedVectorltTgt operator(const
    CheckedVectorltTgt other)
  • (void) vectorltTgtoperator(other)
  • return this
  • Note the syntax to call the operator function
    from the base class.

13
Specifying Changes
  • For our checked vector we want to inherit almost
    all of the functionality from vector. operator
    is about the only thing that should change.
  • T operator(unsigned k)
  • if (k gt size()) abort()
  • return vectorltTgtoperator(k)
  • We need to watch out! Changes are based on the
    NAME of the method, not the signature.

14
Implementing Inheritance
  • The compiler has two responsibilities with
    inheritance.
  • Extend the struct by adding any new fields (note,
    it is not possible to remove or eliminate old
    fields)
  • Support inheritance by allowing the old methods
    to be invoked on the new object WITHOUT
    RECOMPILATION.

15
Extending the Struct
  • With single inheritance, this support is fairly
    simple. All of the new fields are appended to
    the end of the old object.
  • We will talk about this in terms of A Derived
    object has a Base inside it.
  • To invoke a Base function, nothing special is
    required, just pass this as we normally would
    (with single inheritance).
  • All the original fields are accessed using their
    original offsets!

16
The Implied Subtype Relationship
  • This simple implementation trick means that a
    Derived object can be used any place that a Base
    object was expected (their this pointers are the
    same).
  • C provides a subtype (the isa) relationship
    a Derived is a Base
  • Note the reverse relationship would not hold (all
    base objects may not be derived).
  • During type checking, a subtype (derived) can be
    used whenever a supertype is expected (even on
    the right hand side of an equals!)

17
Truncating objects
  • The last bullet on the previous slide had a very
    important point. A base object can be assigned
    (copied) from a derived object.
  • However, the newly created object will only have
    the base part of the original object.
  • Any additional fields will NOT be copied.
  • Pass by value parameters are a common place to
    run into this problem (well see this again
    later).

18
Multiple Inheritance (yuck)
  • There are two distinct problems with multiple
    inheritance.
  • A potential ambiguity arises as a natural result
    of inheriting members from two (or more) base
    classes.
  • The C compilation technique does not elegantly
    support multiple inheritance (like it does for
    single inheritance).

19
Ambiguities with Multiple Inheritance
  • class Base1
  • void doit(void) cout ltlt Im number 1\n
  • class Base2
  • void doit(void) cout ltlt nope, number 2\n
  • class Derived public Base1, Base2
  • Derived d
  • d.doit() // what happens?
  • Programmer must explicitly state which doit is to
    be used.
  • d.Base1doit() d.Base2doit()

20
More Ambiguities and Virtual Inheritance
  • class Counter
  • public
  • static int x
  • Counter(void) x 1
  • int Counterx 0
  • class B1 public Counter
  • class B2 public Counter
  • class D public B1, B2
  • D d // how many times is x incremented?
  • Every D object has two Counters! (x 2).
  • Instead, use virtual inheritance
  • class B1 public virtual Counter
  • class B2 public virtual Counter

21
Implementation Nightmares,Fudging this
  • Besides the potential for confusion, multiple
    inheritance greatly complicates the C
    implementation.
  • Lets assume we have two base classes B1 and B2
    in derived class D.
  • B1s inherited fields will come first in object D
  • B2s inherited fields will come second
  • Ds new fields will be third.
  • If we invoke an inherited B1 method on D, the
    this pointers are the same. BUT if we invoke
    an inherited B2 method, we need to change this!

22
Implementation Pop Quiz
  • Explain what it would take to implement a pointer
    to a member function?
  • First, we must accept that pointers to member
    functions must be kept distinct from pointers to
    functions.
  • The implicit parameter must be passed to member
    functions.
  • Next we need to consider the possibility that the
    pointer to the function could point to an
    inherited function.
  • in the case of multiple inheritance, we might
    have to fudge this to call that function!

23
Other Inheritance Stuff
  • nested types are inherited
  • CheckedVector inherits vectorltTgtiterator
  • can be overridden.
  • A base class can be an instantiation of a
    template (duh, weve done this already).

24
Putting Inheritance to good use
  • The iterator base classes
  • it is tedious to have to define all the umpteen
    different nested types (value_type,
    iterator_category, pointer, reference, etc.) for
    your user-defined iterators.
  • Instead, inherit them!
  • class iterator
  • public iteratorltforward_iterator_tag, Tgt

25
Protected Members
  • To a first approximation, a protected member
    (function or data) is accessible by the class and
    any derived classes.
  • class B
  • protected
  • int x
  • class D public B
  • int value(void) return x
  • Fields are often made protected (rather than
    private).

26
The technical definition
  • class B
  • protected int x
  • void bFun(D d)
  • class D public B
  • void dFun(B b)
  • The variable used to access x must be a subtype
    of the method where the function is called.
  • BbFun(D d)
  • this-gtx // OK
  • d.x // OK
  • DdFun(B b)
  • this-gtx // OK
  • b.x // ERROR

27
Dynamic Binding
  • Recall that the C inheritance mechanism creates
    a subtype relationship
  • Any object of the derived type can be passed to a
    function that expects a parameter of the base
    type.
  • Note that type checking is still static, and the
    function-call mechanism is still 100 compile
    time.
  • In C we use virtual functions to get run-time,
    type-specific behavior.

28
The virtual function
  • non-static member functions can be declared
    virtual.
  • any function with the same signature in derived
    classes must have the same return type.
  • when a virtual function is invoked through a
    pointer or reference to a base type object, the
    correct (inherited or overridden) function is
    executed on the derived object.
  • the determination of which function to invoke is
    made at run time.

29
virtual example
  • class B
  • public
  • //virtual
  • void doit(void) cout ltlt "base\n"
  • class D public B
  • public
  • void doit(void) cout ltlt "derived\n"
  • void foo(B b)
  • b.doit() // if doit is virtual, prints derived
  • int main(void)
  • D d
  • foo(d)

30
Style Suggestions with Virtual
  • the keyword virtual is only required in the base
    class.
  • use virtual in class definition for every derived
    class.
  • virtual-ness applies to the signature, not the
    name.
  • avoid confusion by not overloading virtual
    functions

31
Implementation of Virtual
  • The compiler produces machine code that calls the
    appropriate function using a pointer to the
    function.
  • The pointer is taken from a table.
  • each derived class has a distinct table.
  • Every object has a pointer to the correct table.

32
Implications of Implementation
  • The size of the vf table is linear in the number
    of virtual functions. (e.g. 4X bytes or 8X bytes
    where there are X virtual functions).
  • There is only one table per class. There is one
    pointer (to a table) inside each object. Thus
    the objects are made 4 bytes larger when there is
    a virtual function.
  • The virtual function table provides us the
    ability to determine the type of an object at
    runtime.

33
Replacing Switch Statements with Virtual Functions
  • A switch statement is inconsistent with the
    principles of object-oriented programming.
  • Instead of
  • switch(x-gttype)
  • case A
  • a_operation() break
  • case B
  • b_operation() break
  • Create derived types A and B, and virtual
    function operation in base class (x is ptr to
    base class).
  • x-gtoperation()

34
Functions invoked using this get dynamic binding
  • Functions inherited from the base class can call
    virtual functions from the derived class.
  • class B
  • public
  • virtual const char name(void)return "base"
  • void display_info()
  • cout ltlt "this is the " ltlt name() ltlt "
    class\n"
  • class D public B
  • public
  • virtual const char name(void) return
    "derived"

35
Virtual Destructors
  • The rule of thumb for C is to make your
    destructor virtual if you have at least one
    virtual function.
  • Virtual destructors are important only if you use
    new/delete.
  • When you call delete the destructor is invoked.
  • If you delete a Base pointer that points to a
    Derived object, we still want the derived
    destructor to be called.

36
A C Gotcha with Destructors
  • Once upon a time I wrote a class that did not
    need a destructor. I created a derived class
    that also did not need a destructor.
  • I created instances of the derived class using
    new, and used pointers of the base class to
    reference these objects.
  • I deleted the objects using the pointers I had
    but was surprised to discover a memory leak.
  • I fixed the memory leak by writing a virtual
    destructor in the parent class with an empty body
    . The derived class still did not need a
    destructor.

37
Abstract Functions
  • In object oriented design it is common to have a
    base type which is so general it is abstract.
    i.e., youd never really have an object that was
    just that type. For example, Shape (you could
    have a Circle or a Triangle which might be
    subtypes of Shape).
  • It may not make sense or be possible to implement
    all of the functions in this abstract class.
  • A function is pure virtual if it has no
    implementation.

38
Pure Virtual Syntax and Semantics
  • Syntax
  • class Shape
  • public
  • virtual void draw(void) 0
  • If any virtual function is pure virtual, then the
    class is abstract. You cannot have a variable,
    or return value declared an abstract type.
  • Any derived type must override the pure virtual
    function or else it too will be abstract.

39
When Should a Function be Abstract
  • Keep in mind the consequences if any one
    function is abstract, then the class is abstract
  • If there is no reasonable default implementation
    for the function, or
  • if every subclass should be required to implement
    this function.
Write a Comment
User Comments (0)
About PowerShow.com