CS253: Software Development with C++

Spring 2023

Reflection

Show Lecture.Reflection as a slide show.

CS253 Reflection

Narcissus

Inclusion

To use the class type_info or typeid(), you need to:

    
#include <typeinfo>

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

Really, one rarely actually instantiates a variable of class type_info. You usually just call methods on the temporary object returned by typeid():

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. For your amusement:

cout << typeid(bool              ).name() << '\n'
     << 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';
b
c
h
s
t
i
j
l
m
x
y
f
d
e

Do not memorize these. They vary between compilers, and could change without notice.

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

Name Mangling

Function declarationActual name used by g++
int sum(int, int)_Z3sumii
double sum(int)_Z3sumi
const char *sum()_Z3sumv
bool sum(double, int, short)_Z3sumdis

Polymorphic Example

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

void foo(Base *b) {
    if (typeid(*b) == typeid(D1))
        cout << "It’s a D1\n";
    else if (typeid(*b) == typeid(D2))
        cout << "It’s a D2\n";
}

int main() {
    D1 d1;
    D2 d2;
    foo(&d1);
    foo(&d2);
}
It’s a D1
It’s a D2

dynamic_cast

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

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

Guilt