Skip to main content

RTTI

Oh, do not confuse this word with RTI - right to information. This is not a political blog :).

RTTI - run time type identification is a concept in C++, which gives the type of the object during run time. But it can be used only with polymorphic classes - i.e. the classes which have at least one virtual function.

Typeid

typeid is an operator in C++ which gives the actual type of the object. So what is actual type of object? Is it different from the one we have defined it with?

It may be.

class A
{
public:
   virtual void print(){}
};
class B:public A
{
};
int main()
{
   int a;
   A obj1;
   B obj2;
   A *ptr1 = new B;
}
   

 In the code above, type of a is integer. Type of obj1 is A. Type of obj2 is B.

But what about *ptr1? Is the type of *ptr1 A or B?

typeid operator correctly gives its type as B.

Note : We have added a dummy print function in base class, to make A as polymorphic.

Now let us use typeid operator - which needs the inclusion of header file typeinfo


#include<iostream>
#include<typeinfo>
using namespace std;
class A
{
public:
   virtual void print(){}
};
class B:public A
{
};
int main()
{
   int v1;
   A obj1;
   B obj2;
   A *ptr1 = new B;
   cout<<"Type of v1 is "<<typeid(a).name()<<endl;
   cout<<"Type of obj1 is "<<typeid(obj1).name()<<endl;
   cout<<"Type of *ptr1 is "<<typeid(*ptr1).name()<<endl; 
}
   
 But when you run this program, you may see some strange names instead of class names.

The reason is typeid().name returns mangled name in case of gcc compilers. To get unmangled name, straight forward method is to use

./a.out |c++filt -t
Type of v1 is int
Type of obj1 is A
Type of *ptr1 is B



Next let us see how to use dynamic_cast

Dynamic cast

dynamic_cast is used for safe conversion of variables. It can be used for upcast or even downcast also. If we use correct type for dynamic_cast, we get the required value. If not, the program aborts with type error.


#include<iostream> 
using namespace std;
class A
{
 int na;  
public:
virtual void print()
{
   cout<<"print function of class A"<<endl;
}
};
class B:public A
{
  int nb;
};
class C:public A
{
  int nc;
};
void printDyn(A&obja)
{
  cout<<"We are in printDyn function"<<endl; 
  C &refc = dynamic_cast<C&>(obja);
  cout<<"we call print function";
  refc.print();
}
int main()
{ 
    C objc;
    printDyn(objc);
    B objb;
    printDyn(objb);  
}

In this program in printDyn() function, we are converting the reference parameter to C reference. In the first call printDyn(objc), the code works fine because, objc is a C type object.

But when we call the function with object of B class and try to convert it into C reference, the program gives a bad_cast exception and aborts.

Output of the program will be
./a.out
We are in printDyn function
we call print functionprint function of class A
We are in printDyn function
terminate called after throwing an instance of 'std::bad_cast'
  what():  std::bad_cast
Aborted



Please remember that target of dynamic_cast must be either a pointer or a reference to a class.

You can get these notes and also programs, quiz on C++ by downloading the app Simplified C++ by Hegdeapps 


Comments

Popular posts from this blog

Polymorphism

You hear the term Polymorphism too frequently with object oriented languages. Along with Inheritance and Encapsulation, polymorphism is one of the corner stones of object oriented design. What is Polymorphism, exactly? Polymorphism is a mechanism by which you provide single interface for multiple methods. (poly - many, morph - form). In C++, polymorphism can be compile time or run-time. Compile time polymorphism is provided with the help of overloaded operators/functions and templates. Run time polymorphism is provided with the help of virtual functions and late binding. Late Binding: Connecting a function call to function body is called binding. Most functions use early binding where this binding happens before the program is run - during compile time. This is also called static binding. Late binding (also called dynamic binding)  is when a function call is connected to function body at run time. This is done after looking at the type of the object. Late binding is ach

Operator Overloading

What is operator overloading ? Operator overloading is the process of customizing C++ operators for operands of user defined types.   When you have two objects of a class- num1 and num2 , you can write a function to add them such as  ans = add(num1,num2); That does not look neither simple nor intuitive. You would prefer to write      ans = num1+num2; as you would write expressions for basic data types like integers, floats etc.    This can be done using Operator overloading. Operator overloading lets you write such statements. That is, it lets you call your functions on objects using  +, - ,* etc.    + operator will call addition function on the object (when you write op. overloading function for +). * will call multiply on objects etc. Names of overloaded operator functions start with keyword operator followed by  symbol of the operator. e.g. +, - etc. Unary operator functions take 0 parameters for members. The operand for these function is the object cal

Constant members of a Class

A constant  is a value which can not be modified. As in C, we can have literal constants using #define and we can have enums and we can define a variable to be const .  Let us look at const variables here. By declaring a variable as const , we ensure that it is not modified accidentally. Any modification to a constant will give a compilation error. A const should always be initialized while defining. In the program below,  assignment to pi gives a compiler error because pi is defined as const and code is trying to modify this. int main () { const float pi = 22.0/7 ; int radius = 12 ; radius ++ ; /*ok*/ pi = 3.14 ; /*error*/ }   Constant parameters to functions Even function parameters can be const ant. We have earlier discussed that making a reference parameter as constant will avoid the function from accidentally modifying the argument. void printnum ( int & n) { cout << n ++ ; } void printnum2 ( const int & n) { cout <&l