100 lines
3 KiB
C++
100 lines
3 KiB
C++
/* C++ run-time type info (RTTI) example
|
|
|
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
|
|
Unless required by applicable law or agreed to in writing, this
|
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <cxxabi.h>
|
|
|
|
using std::cout;
|
|
using std::endl;
|
|
using std::string;
|
|
using std::shared_ptr;
|
|
using std::make_shared;
|
|
|
|
class Base;
|
|
class DerivedA;
|
|
class DerivedB;
|
|
|
|
static string demangle(const char* name);
|
|
|
|
class Base
|
|
{
|
|
public:
|
|
virtual ~Base() {} ;
|
|
virtual string name() = 0;
|
|
static shared_ptr<Base> make_random_derived();
|
|
};
|
|
|
|
class DerivedA : public Base
|
|
{
|
|
public:
|
|
string name() override { return "DerivedA"; }
|
|
};
|
|
|
|
class DerivedB : public Base
|
|
{
|
|
public:
|
|
string name() override { return "DerivedB"; }
|
|
};
|
|
|
|
/* Creates either DerivedA or DerivedB, depending on a random number */
|
|
shared_ptr<Base> Base::make_random_derived()
|
|
{
|
|
if (std::rand() % 2 == 0) {
|
|
return make_shared<DerivedA>();
|
|
} else {
|
|
return make_shared<DerivedB>();
|
|
}
|
|
}
|
|
|
|
/* Inside a .cpp file, app_main function must be declared with C linkage */
|
|
extern "C" void app_main()
|
|
{
|
|
/* Demonstrate typeid().name() */
|
|
cout << "Type names of a few objects:" << endl << '\t';
|
|
cout << "Type name of std::cout is: " << demangle(typeid(std::cout).name()) << endl << '\t';
|
|
cout << "Type name of std::cin is: " << demangle(typeid(std::cin).name()) << endl << '\t';
|
|
cout << "Type of app_main is: " << demangle(typeid(app_main).name()) << endl << '\t';
|
|
auto sum = [](int x, int y) -> int { return x + y; };
|
|
cout << "Type name of a lambda function is: " << demangle(typeid(sum).name()) << endl << endl;
|
|
|
|
/* Demonstrate dynamic_cast */
|
|
std::vector<shared_ptr<Base>> objects(5);
|
|
cout << "Generating " << objects.size() << " random objects and printing their types:" << endl;
|
|
std::generate(objects.begin(), objects.end(), Base::make_random_derived);
|
|
for (auto &obj: objects) {
|
|
cout << "obj->name() is: " << obj->name() << endl << '\t';
|
|
cout << "typeid(*obj).name() is: " << demangle(typeid(*obj).name()) << endl << '\t';
|
|
|
|
const DerivedA* cast_to_derived_a = dynamic_cast<DerivedA*>(obj.get());
|
|
const DerivedB* cast_to_derived_b = dynamic_cast<DerivedB*>(obj.get());
|
|
|
|
cout << "dynamic_cast<DerivedA*>(obj)=" << static_cast<const void*>(cast_to_derived_a) << endl << '\t';
|
|
cout << "dynamic_cast<DerivedB*>(obj)=" << static_cast<const void*>(cast_to_derived_b) << endl << endl;
|
|
}
|
|
|
|
cout << "Example finished." << endl;
|
|
}
|
|
|
|
/* Helper function which converts typeid().name() to a human-readable type name */
|
|
static std::string demangle(const char* name)
|
|
{
|
|
int status = 0;
|
|
char* result = abi::__cxa_demangle(name, NULL, NULL, &status);
|
|
string str_result;
|
|
if (status == 0) {
|
|
str_result = result;
|
|
} else {
|
|
str_result = name;
|
|
}
|
|
free(result);
|
|
return str_result;
|
|
}
|