CS253: Software Development with C++

Spring 2020

Reflection

Show Lecture.Reflection as a slide show.

CS253 Reflection

typeid

int alpha;
short beta;
const type_info &ta = typeid(alpha), &tb = typeid(beta);
cout << "type of alpha: " << ta.name() << '\n'
     << "type of beta:  " << tb.name() << '\n'
     << "Equal?  " << boolalpha << (ta==tb) << '\n';
type of alpha: i
type of beta:  s
Equal?  false

Easier

One rarely actually instantiates a variable of class type_info:

float gamma;
cout << "type of gamma: " << typeid(gamma).name();
type of gamma: f

You can also pass a type as an argument to typeid().

cout << "type of double: " << typeid(double).name();
type of double: d

Built-in Types

Every type has a corresponding implementation-defined encoding:

cout << typeid(char              ).name() << '\n'
     << typeid(unsigned char     ).name() << '\n'
     << typeid(short             ).name() << '\n'
     << typeid(unsigned short    ).name() << '\n'
     << typeid(int               ).name() << '\n'
     << typeid(unsigned int      ).name() << '\n'
     << typeid(long              ).name() << '\n'
     << typeid(unsigned long     ).name() << '\n'
     << typeid(long long         ).name() << '\n'
     << typeid(unsigned long long).name() << '\n'
     << typeid(float             ).name() << '\n'
     << typeid(double            ).name() << '\n'
     << typeid(long double       ).name() << '\n';
c
h
s
t
i
j
l
m
x
y
f
d
e

Composite Types

class Foobar {};
cout << typeid(bool *      ).name() << '\n'
     << typeid(const bool *).name() << '\n'
     << typeid(bool ****** ).name() << '\n'
     << typeid(int[3]      ).name() << '\n'
     << typeid(int[3][4][5]).name() << '\n'
     << typeid(char *[]    ).name() << '\n'
     << typeid(main        ).name() << '\n'
     << typeid(Foobar      ).name() << '\n';
Pb
PKb
PPPPPPb
A3_i
A3_A4_A5_i
A_Pc
FivE
Z4mainE6Foobar

Polymorphic Example

For RTTI (Run-Time Type Identification), a class must have at least one virtual function.

struct Base { virtual void foo(){} };
struct D1 : Base {};
struct D2 : Base {};

void foo(Base *b) {
    cout << ((typeid(*b) == typeid(D1)) ? "D1\n" : "D2\n");
}

int main() {
    D1 d1;
    D2 d2;
    foo(&d1);
    foo(&d2);
}
D1
D2

dynamic_cast

dynamic_cast converts a base class pointer to a derived class pointer. If it fails, you get a null pointer.

struct Base { virtual void foo(){} };
struct D1 : Base {};
struct D2 : Base {};

void foo(Base *b) {
    D1 *p = dynamic_cast<D1 *>(b);
    cout << (p ? "D1\n" : "D2\n");
}

int main() {
    D1 d1;
    D2 d2;
    foo(&d1);
    foo(&d2);
}
D1
D2

Guilt