File: dynamiccast.yo

package info (click to toggle)
c%2B%2B-annotations 12.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 13,044 kB
  • sloc: cpp: 24,337; makefile: 1,517; ansic: 165; sh: 121; perl: 90
file content (144 lines) | stat: -rw-r--r-- 5,907 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
The hi(dynamic_cast)tt(dynamic_cast<>) operator is used to convert a base
class pointer or hi(base class: converting to derived class) reference to,
respectively, a i(derived class) pointer or reference. This is also called
emi(down-casting) as direction of the cast is em(down) the inheritance tree.

A dynamic cast's actions are determined i(run-time); it can only be used if
the base class declares at least one virtual member function. For the dynamic
cast to succeed, the destination class's tt(Vtable) must be equal to the
tt(Vtable) to which the dynamic cast's argument refers to, lest the cast fails
and returns 0 (if a dynamic cast of a pointer was requested) or throws a
tt(std::bad_cast) exception (if a dynamic cast of a reference was requested).

In the following example a pointer to the class tt(Derived) is obtained from
the tt(Base) class pointer tt(bp):
        verb(    class Base
    {
        public:
            virtual ~Base();
    };
    class Derived: public Base
    {
        public:
            char const *toString();
    };
    inline char const *Derived::toString()
    {
        return "Derived object";
    }
    int main()
    {
        Base *bp;
        Derived *dp,
        Derived d;

        bp = &d;

        dp = dynamic_cast<Derived *>(bp);

        if (dp)
            cout << dp->toString() << '\n';
        else
            cout << "dynamic cast conversion failed\n";
    })

In the condition of the above tt(if) statement the success of the dynamic
cast is verified. This verification is performed at em(run-time), as the
actual class of the objects to which the pointer points is only known by then.

If a base class pointer is provided, the dynamic cast operator returns 0 on
failure and a pointer to the requested derived class on success.

    Assume a tt(vector<Base *>) is used. The pointers of such a vector may
point to objects of various classes, all derived from tt(Base). A dynamic cast
returns a pointer to the specified class if the base class pointer indeed
points to an object of the specified class and returns 0 otherwise.

We could determine the actual class of an object a pointer points to by
performing a series of checks to find the derived class to which a base class
pointer points. Example:
        verb(    class Base
    {
        public:
            virtual ~Base();
    };
    class Derived1: public Base;
    class Derived2: public Base;

    int main()
    {
        vector<Base *> vb(initializeBase());

        Base *bp = vb.front();

        if (dynamic_cast<Derived1 *>(bp))
            cout << "bp points to a Derived1 class object\n";
        else if (dynamic_cast<Derived2 *>(bp))
            cout << "bp points to a Derived2 class object\n";
    })

Alternatively, a reference to a base class object may be available. In
this case the tt(dynamic_cast) operator throws an i(exception) if the down
casting fails. Example:
        verbinclude(-a examples/badcast.cc)
    In this example the value tt(std::bad_cast) hi(bad_cast) is used. A
tt(std::bad_cast) exception is thrown if the dynamic cast of a reference to a
derived class object fails.

Note the form of the tt(catch) clause: tt(bad_cast) is the name of a type.
Section ref(EMPTYENUM) describes how  such a type can be defined.

The dynamic cast operator is a useful tool when an existing base class cannot
or should not be modified (e.g., when the sources are not available), and a
derived class may be modified instead. Code receiving a base class pointer or
reference may then perform a dynamic cast to the derived class to access the
derived class's functionality.

You may wonder in what way the behavior of the tt(dynamic_cast) differs from
that of the tt(static_cast).

When the tt(static_cast) is used, we tell the compiler that it must convert a
pointer or reference to its expression type to a pointer or reference of its
destination type. This holds true whether the base class declares virtual
members or not. Consequently, all the tt(static_cast)'s actions can be
determined by the compiler, and the following compiles fine:
        verb(    class Base
    {
        // maybe or not virtual members
    };
    class Derived1: public Base
    {};
    class Derived2: public Base
    {};

    int main()
    {
        Derived1 derived1;
        Base *bp = &derived1;

        Derived1 &d1ref = static_cast<Derived1 &>(*bp);
        Derived2 &d2ref = static_cast<Derived2 &>(*bp);
    })

Pay attention to the second tt(static_cast): here the tt(Base) class
object is cast to a tt(Derived2) class reference. The compiler has no problems
with this, as tt(Base) and tt(Derived2) are related by inheritance.

    Semantically, however, it makes no sense as tt(bp) in fact points to a
tt(Derived1) class object. This is detected by a tt(dynamic_cast).  A
tt(dynamic_cast), like the tt(static_cast), converts related pointer or
reference types, but the tt(dynamic_cast) provides a run-time safeguard. The
dynamic cast fails when the requested type doesn't match the actual type of
the object we're pointing at. In addition, the tt(dynamic_cast)'s use is much
more restricted than the tt(static_cast)'s use, as the tt(dynamic_cast) can
only be used for downcasting to derived classes having virtual members.

In the end a dynamic cast is a cast, and casts should be avoided whenever
possible. When the need for dynamic casting arises ask yourself whether the
base class has correctly been designed. In situations where code expects a
base class reference or pointer the base class interface should be all that is
required and using a dynamic cast should not be necessary. Maybe the base
class's virtual interface can be modified so as to prevent the use of dynamic
casts. Start frowning when encountering code using dynamic casts. When using
dynamic casts in your own code always properly document why the dynamic cast
was appropriately used and was not avoided.