1 /* C++ run-time type info (RTTI) example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 
10 #include <iostream>
11 #include <memory>
12 #include <vector>
13 #include <algorithm>
14 #include <cxxabi.h>
15 
16 using std::cout;
17 using std::endl;
18 using std::string;
19 using std::shared_ptr;
20 using std::make_shared;
21 
22 class Base;
23 class DerivedA;
24 class DerivedB;
25 
26 static string demangle(const char* name);
27 
28 class Base
29 {
30 public:
~Base()31     virtual ~Base() {} ;
32     virtual string name() = 0;
33     static shared_ptr<Base> make_random_derived();
34 };
35 
36 class DerivedA : public Base
37 {
38 public:
name()39     string name() override { return "DerivedA"; }
40 };
41 
42 class DerivedB : public Base
43 {
44 public:
name()45     string name() override { return "DerivedB"; }
46 };
47 
48 /* Creates either DerivedA or DerivedB, depending on a random number */
make_random_derived()49 shared_ptr<Base> Base::make_random_derived()
50 {
51     if (std::rand() % 2 == 0) {
52         return make_shared<DerivedA>();
53     } else {
54         return make_shared<DerivedB>();
55     }
56 }
57 
58 /* Inside a .cpp file, app_main function must be declared with C linkage */
app_main()59 extern "C" void app_main()
60 {
61     /* Demonstrate typeid().name() */
62     cout << "Type names of a few objects:" << endl << '\t';
63     cout << "Type name of std::cout is: " << demangle(typeid(std::cout).name()) << endl << '\t';
64     cout << "Type name of std::cin is: "  << demangle(typeid(std::cin).name()) << endl << '\t';
65     cout << "Type of app_main is: " << demangle(typeid(app_main).name()) << endl << '\t';
66     auto sum = [](int x, int y) -> int { return x + y; };
67     cout << "Type name of a lambda function is: "  << demangle(typeid(sum).name()) << endl << endl;
68 
69     /* Demonstrate dynamic_cast */
70     std::vector<shared_ptr<Base>> objects(5);
71     cout << "Generating " << objects.size() << " random objects and printing their types:" << endl;
72     std::generate(objects.begin(), objects.end(), Base::make_random_derived);
73     for (auto &obj: objects) {
74         cout << "obj->name() is: " << obj->name() << endl << '\t';
75         cout << "typeid(*obj).name() is: " << demangle(typeid(*obj).name()) << endl << '\t';
76 
77         const DerivedA* cast_to_derived_a = dynamic_cast<DerivedA*>(obj.get());
78         const DerivedB* cast_to_derived_b = dynamic_cast<DerivedB*>(obj.get());
79 
80         cout << "dynamic_cast<DerivedA*>(obj)=" << static_cast<const void*>(cast_to_derived_a) << endl << '\t';
81         cout << "dynamic_cast<DerivedB*>(obj)=" << static_cast<const void*>(cast_to_derived_b) << endl << endl;
82     }
83 
84     cout << "Example finished." << endl;
85 }
86 
87 /* Helper function which converts typeid().name() to a human-readable type name */
demangle(const char * name)88 static std::string demangle(const char* name)
89 {
90     int status = 0;
91     char* result = abi::__cxa_demangle(name, NULL, NULL, &status);
92     string str_result;
93     if (status == 0) {
94         str_result = result;
95     } else {
96         str_result = name;
97     }
98     free(result);
99     return str_result;
100 }
101