Skip to content

Commit e8e52dc

Browse files
committed
Expand type_casting
1 parent 5abdcef commit e8e52dc

File tree

1 file changed

+88
-22
lines changed

1 file changed

+88
-22
lines changed

src/type_casting_main.cpp

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,19 @@
2727
//
2828
// License: MIT
2929
//========================================================================
30+
#include "cppt_tools.hpp"
31+
#include "cppt_ag.hpp"
32+
3033
#include <cstdint>
3134
#include <iostream>
3235
#include <typeinfo>
3336

34-
#include "cppt_ag.hpp"
3537

3638
//========================================================================
3739
// Data structures
3840
//========================================================================
3941
//------------------------------------------------------------------------
40-
// A and B are related through B's constructors
42+
// A and B are related through B's constructors - NON-VIRTUAL
4143
//------------------------------------------------------------------------
4244
struct A {
4345
A() { std::cout << " A()" << std::endl; }
@@ -49,7 +51,7 @@ struct B {
4951
};
5052

5153
//------------------------------------------------------------------------
52-
// C is unrelated to A and B
54+
// C is unrelated to A and B - NON-VIRTUAL
5355
//------------------------------------------------------------------------
5456
struct C {
5557
C(int32_t a, int32_t b) : x(a), y(b) {
@@ -63,7 +65,8 @@ struct C {
6365
};
6466

6567
//------------------------------------------------------------------------
66-
// E inherits from D (note that it contains data not present in D)
68+
// E inherits from D - VIRTUAL
69+
// (note that E contains data not present in D)
6770
//------------------------------------------------------------------------
6871
struct D {
6972
D() { std::cout << " D()" << std::endl; }
@@ -80,31 +83,61 @@ struct E : public D {
8083
int32_t some_int = 123;
8184
};
8285

86+
//------------------------------------------------------------------------
87+
// Unrelated classes - VIRTUAL
88+
//------------------------------------------------------------------------
89+
90+
struct F{
91+
virtual int g() {return 4;}
92+
};
93+
94+
struct G{
95+
virtual int h() {return 6;}
96+
};
97+
8398
//========================================================================
8499
// main
85100
//========================================================================
86-
int main() {
101+
int main(int argc, const char** argv) {
102+
cppt::header(argv[0]);
103+
size_t sec_num = {1};
104+
105+
//-------------------------------------------------------------------------
87106
// 1. ===> IMPLICIT CONVERSION <===
88-
std::cout << "1. IMPLICIT CONVERSION:" << std::endl;
107+
//-------------------------------------------------------------------------
108+
std::cout << "========================================================" << std::endl;
109+
std::cout << "===> IMPLICIT CONVERSION <===" << std::endl;
110+
std::cout << "========================================================" << std::endl;
111+
std::cout << sec_num++ << ". Cost through constructors:" << std::endl;
89112

90-
// 1.1 Cast between different integer types
113+
// Cast between different integer types
91114
int16_t var_a = 2000;
92115
int32_t var_b = var_a;
116+
std::cout << " Size and type of var_a: " << sizeof var_a << ", "
117+
<< typeid(var_a).name() << std::endl;
118+
std::cout << " Size and type of obj_B: " << sizeof var_b << ", "
119+
<< typeid(var_b).name() << std::endl;
93120

94-
// 1.2 Implicit conversion through a specialised constructor
121+
// Implicit conversion through a specialised constructor
95122
A obj_A;
96123
B obj_B = obj_A;
97124

98-
std::cout << " Size and type of obj_A: " << sizeof obj_A << " "
125+
std::cout << " Size and type of obj_A: " << sizeof obj_A << ", "
99126
<< typeid(obj_A).name() << std::endl;
100-
std::cout << " Size and type of obj_B: " << sizeof obj_B << " "
127+
std::cout << " Size and type of obj_B: " << sizeof obj_B << ", "
101128
<< typeid(obj_B).name() << std::endl;
102129

130+
//-------------------------------------------------------------------------
103131
// 2. ===> EXPLICIT CONVERSION <===
104-
std::cout << "2. EXPLICIT CONVERSION:" << std::endl;
132+
//-------------------------------------------------------------------------
133+
std::cout << "========================================================" << std::endl;
134+
std::cout << "===> EXPLICIT CONVERSION <===" << std::endl;
135+
std::cout << "========================================================" << std::endl;
105136

106-
// 2.1 C-STYLE CASTS
107-
std::cout << " 2.1 C-style cast:" << std::endl;
137+
//-------------------------------------------------------------------------
138+
// C-STYLE CASTS
139+
//-------------------------------------------------------------------------
140+
std::cout << sec_num++ << ". C-style cast:" << std::endl;
108141

109142
// 2.1.1 Cast between 16 and 32 bit integer types (good example)
110143
int32_t var_c = (int32_t)var_a;
@@ -119,32 +152,59 @@ int main() {
119152
<< std::endl;
120153
#endif
121154

155+
//-------------------------------------------------------------------------
122156
// 2.2 DYNAMIC_CAST<T>
123157
// Used for conversion of polymorphic types. Does runtime check of the types.
124158
// Returns nullptr if the conversion is not possible (so remember to check
125159
// the output!)
126-
std::cout << " 2.2 dynamic_cast<T>:" << std::endl;
160+
//-------------------------------------------------------------------------
161+
std::cout << sec_num++ << ". dynamic_cast<T> (related classes):" << std::endl;
162+
163+
#ifdef COMPILATION_ERROR
164+
// Only polymorphic classes can be dynamic_cast'ed!
165+
C* p_obj_C2 = dynamic_cast<C*>(&obj_A);
166+
#endif
127167

128168
D obj_D;
129169
E obj_E;
130170
D* p_obj_D;
131171
E* p_obj_E;
132172

133-
// 2.2.1 Cast derived to base (fine)
173+
// 2.2.1 Cast derived to base - fine!
134174
p_obj_D = dynamic_cast<D*>(&obj_E);
135-
if (p_obj_D == nullptr) {
136-
std::cout << " Null pointer on 1st dynamic_cast" << std::endl;
175+
if (p_obj_D != nullptr) {
176+
std::cout << " dynamic_cast of a derived class to its base is fine!" << std::endl;
137177
}
138178

139-
// 2.2.2 Cast base to derived (bad)
179+
// 2.2.2 Cast base to derived - bad!
140180
p_obj_E = dynamic_cast<E*>(&obj_D);
141181
if (p_obj_E == nullptr) {
142-
std::cout << " Null pointer on 2nd dynamic_cast" << std::endl;
182+
std::cout << " dynamic_cast of a base clase to one of its derived classes is bad!" << std::endl;
143183
}
144184

185+
std::cout << sec_num++ << ". dynamic_cast<T> (unrelated classes):" << std::endl;
186+
F *f1 = nullptr;
187+
G *g1 = dynamic_cast<G*>(f1);
188+
if (!g1) {
189+
std::cerr << "Nice try - trying to dynamic_cast a nullptr yields a nullptr!\n";
190+
}
191+
F f2;
192+
G *g2 = dynamic_cast<G*>(&f2);
193+
if (!g2) {
194+
std::cerr << "Nice try - trying to dynamic_cast unrelated types yields a nullptr!\n";
195+
}
196+
try {
197+
F f3;
198+
G &g3 = dynamic_cast<G&>(f3);
199+
} catch(std::bad_cast &) {
200+
std::cerr << "Nice try - trying to dynamic_cast unrelated referneces throws a bad_cast exception!\n";
201+
}
202+
203+
//-------------------------------------------------------------------------
145204
// 2.3 STATIC_CAST<T>
205+
//-------------------------------------------------------------------------
146206
// Used for conversion of non-polymorphic types. Doesn't do runtime checks.
147-
std::cout << " 2.3 static_cast<T>:" << std::endl;
207+
std::cout << sec_num++ << ". static_cast<T>:" << std::endl;
148208

149209
// 2.3.1 Cast between numeric types (good)
150210
double var_d = 3.14159265;
@@ -160,11 +220,13 @@ int main() {
160220
p_obj_E->print();
161221
#endif
162222

223+
//-------------------------------------------------------------------------
163224
// 2.4 REINTERPRET_CAST<T>
225+
//-------------------------------------------------------------------------
164226
// Allows any pointer to be converted into any other pointer type. Also allows
165227
// any integral type to be converted into any pointer type and vice versa. No
166228
// runtime checks are performed.
167-
std::cout << " 2.4 reinterpret_cast<T>:" << std::endl;
229+
std::cout << sec_num++ << ". reinterpret_cast<T>:" << std::endl;
168230

169231
// 2.4.1 Cast one pointer type to another pointer type - bad, bad, bad!
170232
A* p_obj_A = &obj_A;
@@ -180,9 +242,11 @@ int main() {
180242
// Bad, bad, bad!
181243
p_obj_A = reinterpret_cast<A*>(var_j);
182244

245+
//-------------------------------------------------------------------------
183246
// 2.5 CONST_CAST<T>
247+
//-------------------------------------------------------------------------
184248
// Used to remove the const, volatile, and __unaligned attributes.
185-
std::cout << " 2.5 const_cast<T>:" << std::endl;
249+
std::cout << sec_num++ << ". const_cast<T>:" << std::endl;
186250

187251
// 2.5.1 Modify a non-const variable through a reference-to-const (good
188252
// example)
@@ -200,4 +264,6 @@ int main() {
200264
const_cast<int32_t&>(rcl) = 4;
201265
std::cout << " The value of var_l: " << var_l << std::endl;
202266
#endif
267+
268+
cppt::footer(argv[0]);
203269
}

0 commit comments

Comments
 (0)