Case Studies and Examples in Object Oriented Programming - PowerPoint PPT Presentation

1 / 38
About This Presentation
Title:

Case Studies and Examples in Object Oriented Programming

Description:

Even the last option fails unless the programmer knows the actual type of the object. ... Please fudge the time by a small amount (increase by a factor of 1.001) ... – PowerPoint PPT presentation

Number of Views:1392
Avg rating:3.0/5.0
Slides: 39
Provided by: usersEc3
Category:

less

Transcript and Presenter's Notes

Title: Case Studies and Examples in Object Oriented Programming


1
Case Studies and Examples in Object Oriented
Programming
2
Virtual Copy
  • Problem Given a reference to an object, create a
    duplicate object.
  • the constructor will not work!
  • Base b // some object
  • Base x new Base(b) // Nope. makes a base
  • Derived y new Base(b) // Nope, illegal
  • Derived z new
  • Derived(dynamic_castltDerivedgt(b)) // YUCK!
  • Even the last option fails unless the programmer
    knows the actual type of the object.

3
Virtual Copy
  • A constructor cannot be virtual, but we can have
    a virtual function that acts a lot like a
    constructor
  • class Base
  • Base copy(void) const 0 // make a duplicate
  • Every object implements a trivial copy
  • class Derived public Base
  • Base copy(void) const
  • return new Derived(this)

4
Smart Pointers
  • Note that the virtual copy function must return a
    pointer into the heap.
  • How do we ensure that this object is eventually
    reclaimed?
  • Use garbage collector
  • Use smart pointers.
  • The C standard includes an auto_ptr that will
    automatically delete objects.

5
auto_ptr semantics
  • When the auto_ptr goes out of scope, the object
    it points to is automatically destroyed
  • No two auto_ptrs should point at the same object!
  • The assignment operation sets the right hand side
    to nil.
  • The only way to make two auto_ptrs point at the
    same object is to construct both of them from the
    same base pointer.

6
template ltclass Tgt class auto_ptr T
ptr public explicit auto_ptr(T p 0)
ptr(p) auto_ptr(auto_ptr a)
ptr(a.release()) auto_ptr
operator(auto_ptr a) if (a ! this)
delete ptr ptr a.release()
return this auto_ptr() delete ptr
T release() T tmp ptr ptr 0
return tmp
7
Wrappers
  • A Wrapper is similar (in implementation) to a
    smart pointer. However, a does not look like a
    pointer.
  • A wrapper has member functions for each of the
    methods of the wrapped object.
  • Users of the wrapper do not even need to know
    that an inheritance hierachy exists.

8
Using Wrappers to Morph Shapes
  • Consider an inheritance hierarchy with _Shape as
    the abstract base, and draw(), copy() and morph()
    as virtual members.
  • both copy() and morph() return newly allocated
    _Shape objects from the heap.
  • class Shape
  • _Shape shape
  • public
  • void draw(void) const shape-gtdraw()
  • Shape(const Shape other)
  • shape other.copy()

9
More with the Shape Wrapper
  • void morph(void)
  • _Shape t shape-gtmorph()
  • delete shape
  • shape t
  • The Wrapper has a real copy constructor (and
    should have an assignment operator)

10
Object Oriented Creation
  • In an object oriented design are goals are
  • Implement the application with knowledge of only
    the base class.
  • Implement the subclasses independently of each
    other.
  • How can we create objects and still maintain
    these two objectives?

11
Factory Method
  • A Factory method is a function that creates a new
    object. Lets assume that the information we
    need to determine the type of object to be
    created comes from the input stream
  • Base my_factory(void)
  • cin gtgt type
  • switch (type)
  • case type_1 return new Derived1()
  • case type_2 return new Derived2()

12
Using Prototypes
  • What if we have a hash table filled with
    representative objects?
  • Base my_factory(void)
  • cin gtgt type
  • Base prototype table.lookup(type)
  • return prototype-gtcopy()
  • Much closer to our objectives, the factory can be
    written with no knowledge of the derived types.

13
Using Functions
  • The drawback of the prototype pattern is that
    each object must be an exact copy of some
    original. What if there are more parameters (in
    the input stream?) that need to be used to
    construct the new object?
  • Instead of putting a representative object into
    the hash table, put a function.
  • This function can read the params from the input
    and create the appropriate object.

14
Initialization
  • Our factory method will only work correctly if
    the hash table is initialized before the first
    use.
  • ideally, each subtype would install its own
    entry into the hash table!
  • Accomplishing this feat reliably in C involves
    creating initialization objects with static
    linkage (and a few other tricks).

15
Returning References to static locals
  • class Base
  • static HashTable hash_table(void)
  • static HashTable ht
  • return ht
  • public
  • static void insert_table(Key k, Function f)
  • hash_table().insert(k, f)

16
Static Linkage for Initializers
  • Place this code in Derived.h
  • class Derived_Initializer
  • public
  • Derived_Initializer(void)
  • static bool inserted_already false
  • if (inserted_already) return
  • Baseinsert_table(Derived_Key, Derived_Fun)
  • inserted_already true
  • static Derived_Initializer __derived_initializer

17
Simulation
  • Object oriented programming was invented to
    support simulation.
  • The first object oriented language was Simula,
    a language designed to support simulation.
  • Well discuss event-driven simulation.

18
Events
  • Nothing interesting happens between events.
  • All computation takes place as a result of
    processing events.
  • Events are application-specific actions that take
    place in the simulated world.
  • For example, if we were simulating a network
    switch the events could be
  • packets arriving at the switch
  • packets departing the switch.

19
Simulation Time
  • Events are processed in the order that they occur
    in the simulation world.
  • Every event has a time stamp. The time is
    simulation time (not real time).
  • When an event is created, its time stamp must be
    some time in the future.
  • Simulation time advances in jumps as events are
    processed.
  • Events are kept in a priority queue, sorted by
    time stamp.
  • The rate at which simulation time advances is
    determined solely by the time stamps in the
    events.

20
Selecting Your Events
  • Selecting the events for your simulation is the
    most important (and sometimes most challenging)
    part of designing a simulation.
  • Everything interesting must be an event
  • Some not-quite interesting events may be
    processed too
  • must err on the safe side, not to miss anything.

21
Simulation State
  • The second most important design decision for a
    simulation is determining how much information to
    keep in the simulation state.
  • The more information, the slower the simulation
    will run.
  • This problem is mitigated by updating only part
    of the state at each event. As events are
    processed, some of the state information may be
    stale!

22
Object-Oriented State
  • The simulation state is a natural application of
    object oriented programming.
  • There is often natural correspondence between the
    data structures and physical objects.
  • The ability to use OO polymorphism helps simplify
    the program structure.

23
The LifeForm
  • In our example, the simulation state will be
    represented by the state of the LifeForm objects.
  • LifeForm is an abstract base class with the
    following fields
  • pos the last known position
  • course the last known direction it was traveling
  • speed the last known speed at which it was
    moving
  • energy how strong the life form is.
  • plus a few other fields useful for the simulation.

24
The Craig Sub Type
  • The actual life forms in our simulation will be
    concrete sub types of LifeForm, for example
    Craig.
  • A Craig object inherits the position, energy,
    etc. fields, but cannot access these fields
    directly.
  • No subtype of LifeForm can ever be allowed to
    determine its absolute position!
  • There will be some simulation events defined by
    the LifeForm base class
  • and some events defined by the subtypes.

25
A Representative Event
  • Assume that a Craig life form will change
    direction at time 10.
  • We need to write a method that will be called
    when this event occurs Craigturn().
  • We need to create an event that will cause this
    method to be invoked on the correct object at the
    correct moment in simulation time.

26
The Turn Method for Craig
  • void Craigturn(void) // note no params
  • double course get_course()
  • course course M_PI / 2 // turn left
  • set_course(course)
  • get_course and set_course are methods inherited
    from the base class. If implemented correctly,
    the object has now turned 90 degrees to the left.
  • We have several choices for making event objects
    that will invoke this function

27
A Pure OOP Style
  • class LifeFormEvent
  • double timestamp
  • public
  • virtual void doit(void) 0
  • class CraigTurnEvent public LifeFormEvent
  • Craig obj
  • public
  • void doit(void) obj-gtturn()
  • Now we just need to create a CraigTurnEvent with
    the appropriate time stamp and pointer to the
    correct Craig object and insert this event into
    the event queue.

28
Comments on OOP Events
  • Its a bit tedious to create these event objects.
  • For every event we have to write an entire class,
    with constructors, etc.
  • C at least allows the classes to be defined
    with scope local to a function.
  • This will help us avoid name clashes, since
    everyone will probably create an event called
    MyEvent.

29
Pointers to Functions
  • Since we had to write the function Craigturn
    anyway, why not just stick a pointer to that
    function in the event and avoid having to create
    a whole new Event subclass?
  • Whoops, Craigturn is a member function, so the
    event will still need an object to invoke this
    function.
  • Still this will be easier to create.

30
Comments on Pointers
  • From a performance standpoint, the
    pointers-to-member functions does not really hurt
    us.
  • Virtual functions are implemented using pointers
    to functions.
  • In theory, using the pointer-to-member could
    allow us to avoid using the virtual doit()
    function in the Event Base class.
  • BUT A Pointer to a member function cannot point
    to a member function in a derived class!

31
A Combined Approach With Templates
  • The advantage of the pointer-to-function approach
    was that it was less trouble to create a new
    event.
  • The problem was the type of the pointer.
  • Aha! use templates.
  • Well create a base class Event, and have a
    template class as a subtype.

32
Canceling Events
  • It is frequently the case that the processing of
    an event defines new events for the future.
  • Occasionally, the processing of an event results
    in a future event no longer being relevant.
  • How can we stop these events?
  • The LifeForm event class can be deleted. When an
    event is deleted it is automatically removed from
    the event queue.
  • Be sure you only delete events that have not yet
    occurred!

33
LifeForm Movement
  • In our simulation, we dead reckon the objects
    position.
  • Each time we update the pos field, we also record
    the time stamp.
  • At any future time, we can calculate the objects
    position by subtracting the time of the last
    update from the current time, multiplying this by
    the speed and adding the distance traveled to the
    objects current position.

34
Boundary Crossings
  • LifeForms may eventually encounter (physically
    collide with) other LifeForms.
  • We know that this event cannot happen unless at
    least one of the two LifeForms crosses a boundary
    in the QuadTree.
  • Therefore, we should check for a possible
    collision each time an object crosses a boundary.

35
Scheduling the Boundary Crossing Event
  • When an object is inserted into the QuadTree, the
    object is placed into a rectangular region.
  • We can ask the QuadTree what is the distance
    (scalar) that the object must travel along some
    defined course in order to leave its current
    region.
  • Knowing this distance, we can calculate when the
    object will leave its region.
  • Please fudge the time by a small amount (increase
    by a factor of 1.001). This trick will avoid
    problems with floating point roundoff.

36
Using the QuadTree
  • You must not change the position variable while
    an object is in the QuadTree.
  • You can lose the object this way!
  • Instead, you may
  • remove the object from the tree, update the pos
    field, and then re-insert the object.
  • invoke the update_position function on the
    QuadTree (and then change the pos field).
  • Do not insert two objects at the same position.
  • You can ask the QuadTree if a position
    is_occupied.

37
QuadTree Callbacks
  • We check for collisions when objects cross region
    boundaries.
  • Event is scheduled to occur at this time.
  • What happens when new objects are inserted and
    the region gets smaller?
  • We may cross the border and collide with the new
    object BEFORE the event!!!
  • The QuadTree will invoke a callback on any object
    whos region has changed size since the object
    was last inserted.
  • The callback must be inserted along with the
    object.

38
Changing Course
  • When a LifeForm changes course, we should update
    the position!
Write a Comment
User Comments (0)
About PowerShow.com