Run-time type information (RTTI) and casts - PowerPoint PPT Presentation

About This Presentation
Title:

Run-time type information (RTTI) and casts

Description:

Suppose we want to call resetToDefault for all the CheckBoxes in a window. ... We can just call resetToDefault for every component in the window. ... – PowerPoint PPT presentation

Number of Views:51
Avg rating:3.0/5.0
Slides: 23
Provided by: hawb3
Category:
Tags: rtti | casts | information | run | time | type | window

less

Transcript and Presenter's Notes

Title: Run-time type information (RTTI) and casts


1
Run-time type information (RTTI) and casts
  • Consider classes for components and windows
  • class Component
  • ...
  • virtual void draw()
  • class Window public Component
  • ...
  • virtual void addComponent(Component c)
  • virtual listltComponentgt getAllComponents()

2
  • CS 213
  • Fall 1998
  • Run-time type information (RTTI)
  • and casts

3
  • class Component ... virtual void draw()
  • class Window public Component
  • ...
  • virtual void addComponent(Component c)
  • virtual listltComponentgt getAllComponents()
  • class Border public Component ...
  • class Menu public Component ...
  • class CheckBox public Component
  • ...
  • virtual void resetToDefault()
  • Suppose we want to call resetToDefault for all
    the CheckBoxes in a window. We can use
    getAllComponents to find all the components, and
    then we can loop through the components to reset
    each CheckBox.

4
  • class Window public Component
  • ...
  • virtual void addComponent(Component c)
  • virtual listltComponentgt getAllComponents()
  • void resetAllCheckBoxes(Window w)
  • listltComponentgt l w-gtgetAllComponents()
  • for(listltComponentgtiterator i l.begin()
  • i ! l.end() i)
  • Component c i
  • ... // is c a CheckBox???
  • But what do we do for each component c? If c is
    a CheckBox, wed like to call resetToDefault.
    But how do we know whether c is a CheckBox?

5
  • First, lets try to avoid the problem. Maybe all
    components should have a resetToDefault function
    in them
  • class Component
  • ...
  • virtual void draw()
  • virtual void resetToDefault()
  • So then we can call resetToDefault for each
    component in the list.
  • But this is lousy - why should, say, a Border
    have a resetToDefault function? What if
    Component was written by a different company than
    CheckBox? Why should the authors of Component
    have to be aware that some derived classes will
    have a resetToDefault function?

6
  • perhaps Window could be a template class
  • template ltclass Tgt
  • class Window public Component
  • ...
  • virtual void addComponent(T c)
  • virtual listltTgt getAllComponents()
  • So if we create a WindowltCheckBoxgt, then we know
    every component in the window supports the
    resetToDefault function.
  • But this isnt appropriate here - a
    WindowltCheckBoxgt can only support CheckBoxes, and
    not Menus or Borders. So this is too
    restrictive.

7
  • The two approaches just described avoid the need
    for determining types at run-time
  • Add more functions to the base class if every
    component supports resetToDefault, then we dont
    have to figure out which components are
    CheckBoxes and which arent. We can just call
    resetToDefault for every component in the window.
  • Use templates if every component in the Window
    is a CheckBox, then every component must support
    resetToDefault
  • In general, these are the preferred technique to
    use C.
  • But sometimes, neither of these techniques is
    adequate. This is especially true when we hand
    an object (like a CheckBox) to a system that
    someone else wrote (like Window), and this system
    hands our object back to us with less type
    information. In this case, we lost the exact
    type of the CheckBox, and we know only that it is
    a Component.

8
  • To deal with this, C adds a special type of
    cast that checks the type of an object at
    run-time
  • ...
  • Component c ...
  • CheckBox checkBox dynamic_castltCheckBoxgt(c)
  • if(checkBox ! NULL) checkBox-gtresetToDefault()
  • dynamic_castltCheckBoxgt(c) examines the type of c
    at run-time, and if c is a pointer to a CheckBox
    (or if c is a pointer to an object of a type
    derived from CheckBox), then the cast returns a
    pointer to the CheckBox.
  • Otherwise, the cast returns NULL, indicating that
    c does not point to a CheckBox.

9
  • Note that dynamic_cast is very different from a
    C-style cast
  • Component c ...
  • CheckBox checkBox (CheckBox)(c) // C-style
    cast
  • checkBox-gtresetToDefault()
  • The C-style cast assumes that c points to a
    CheckBox, whether it actually does or not! No
    run-time check is performed. So if c points to a
    Border or Menu, the above code will probably
    crash.

10
  • C defines four different cast operators
  • dynamic_cast
  • static_cast
  • reinterpret_cast
  • const_cast
  • dynamic_cast is the safest of these. It can only
    be used on classes that have virtual functions.
    It cannot be used, for instance, to cast a double
    to an int.

11
  • dynamic_cast can be used to navigate a class
    hierarchy

Window
Window_with_border
Window_with_menu
Clock
12
  • dynamic_cast can be used to navigate a class
    hierarchy
  • An upcast requires no explicit cast
  • Clock c ...
  • Window_with_border w c // No cast needed
  • This is because all Clocks are Window_with_borders
    .

Window
Window_with_border
Window_with_menu
Clock
upcast
13
  • dynamic_cast can be used to navigate a class
    hierarchy
  • A downcast requires an explicit cast
  • Window_with_border w ...
  • Clock c dynamic_castltClockgt(w) // Explicit
    cast needed
  • This is because not all Window_with_borders are
    Clocks.

Window
Window_with_border
Window_with_menu
Clock
downcast
14
  • dynamic_cast can be used to navigate a class
    hierarchy
  • A crosscast also requires an explicit cast
  • Window_with_border wb ...
  • Window_with_menu wm
  • dynamic_castltWindow_with_menugt(wb)//Explicit
    cast needed
  • This is because not all Window_with_borders are
    Window_with_menus.

Window
Window_with_border
Window_with_menu
crosscast
Clock
15
  • Upcasts, downcasts, and crosscasts can change the
    address that a pointer points to. For instance,
    after the crosscast, wm and wb point to different
    locations within a single Clock object

Clock data
Window data
wb
Window_with_border data
ptr
wm
Window_with_menu data
ptr
16
  • dynamic_casts on pointers return NULL if the cast
    fails
  • Component c ...
  • CheckBox checkBox dynamic_castltCheckBoxgt(c)
  • if(checkBox ! NULL) checkBox-gtresetToDefault()
  • dynamic_casts can also be used on references
  • Component c ...
  • CheckBox checkBox dynamic_castltCheckBoxgt(c)
  • If a dynamic_cast fails on a reference, a
    bad_cast exception is thrown.

17
  • static_cast isnt as safe as dynamic_cast. It
    can do downcasts if you are absolutely sure the
    cast is correct
  • Window_with_border w ...
  • Clock c static_castltClockgt(w)
  • However, no run-time check is performed, so this
    may lead to a crash if w isnt really a Clock.
    Its safer to use dynamic_cast.
  • static_cast cannot be used for crosscasts.

18
  • So why would anyone use static_cast?
  • Its somewhat faster, since no run-time check is
    performed. (But this shouldnt be your major
    concern, since you dont use casts very often
    anyway.)
  • It can also be used to cast from void, which is
    useful when interfacing to old C code
  • void v ...
  • Clock c static_castltClockgt(v)
  • dynamic_cast cant be used here, since void
    isnt necessarily a pointer to a class with
    virtual functions.

19
  • reinterpret_cast is used for low-level bits
    hacking, such as converting a pointer to an
    integer
  • Component c ...
  • int i reinterpret_castltintgt c
  • This is highly implementation dependent, and very
    dangerous.

20
  • Finally, const_cast is used to ignore the
    constness of a value
  • const int i ...
  • int k const_castltintgt
  • This isnt very tasteful, but is sometimes
    necessary when interfacing const-aware code with
    const-unaware code.

21
  • You should use casts rarely. If you do need to
    use a cast, remember that some casts are safer
    than others
  • const_cast safe (not necessarily tasteful, but
    sometimes necessary)
  • dynamic_cast safe, as long as you check the
    result to see if it is equal to NULL.
  • static_cast dangerous needed for cast from
    void, otherwise dynamic_cast is usually better
  • reinterpret_cast really dangerous, needed only
    for low-level bits hacking
  • The most dangerous of all is the C-style cast,
    which is deprecated in C. A C-style cast is an
    unpredictable mixture of const_cast, static_cast,
    and reinterpret_cast.

22
  • dynamic_cast used run-time type information about
    an object. This run-time information is also
    available to programmers directly. The typeid
    operator returns a type_info object for an
    expression or type
  • type_info ti typeid(e)
  • type_info contains a name function to print the
    name of a type. This can be useful for
    diagnostics
  • Component c
  • cout ltlt typeid(c).name() ltlt endl
  • Like dynamic_cast, typeid only works for classes
    with virtual functions.
Write a Comment
User Comments (0)
About PowerShow.com