Type Conversions in Class Hierarchies
Overview
When we work with user-defined data types in class hierarchies, the type conversion occurs due to some kind of assignment of one type into another. The consequences of the assignment and conversions seem to appear in the access of the data. It can be either implicit, i.e., all functionality is to be done automatically by inbuilt constructs and compiler, or explicit, i.e., programmer has to write some extra code which will eventually typecast the one data type to another.
Implicit Type Conversions
The derived class inherits the public properties and methods of the base class. The objects created by the derived class are considered as a specialization of the generalized Base class and exhibit the Is-A property;
For example, If we have student as a derived class object and person as the base class object, then student is a person.
So the point of introducing this fact is that we can somehow assign the derived class object to the parent class object and it will normally cause an implicit type conversion because the specialization can always be fitted to the generalization.
Recall the Basic Conversion of float to int where the 4.56(assume) can be typecast to 4 because the more can always fill less. The same thing is going on here in user-defined data types.
To implement and examine the concepts of the type conversions in class hierarchies, we have to create a class and at least one derived class.
Here we have Person as a base class, which consists of name and age as private properties and two access methods along with a constructor. The display method will be used to print the information about a person's object. The Student is a derived class, along with inherited ones it consists of grades and standards as properties, Later there are access methods and constructors. The display method is an overload that will be used to print the information of student objects.
Assignment
The implicit conversion in class hierarchies occurs during these assignments.
1. Base class objects
If we assign any object which belongs to the derived class, to the base class object, the data members which are defined in the base class will be copied by the effect of implicit conversion.
The object which is on the right side of the assignment will always contain more information, so the intersection of data will be copied to the base class object.
This image shows that when we assign the Student object to the Person object, only the common properties will be copied.
Output:-
Let's have a look at the consequences of this assignment. As now, we have assigned the derived class object to the base class object, so only the public interface of the Base Class will be accessible by this base class object.
Suffice to say, the information which is extra in the derived class will be ignored during typecasting because the base class object is not capable of handling it.
p1.getStandard(); // Will cause an error: ‘class Person’ has no member named ‘getStandard’
2. Base Class Pointer
As you might know from the concepts of inheritance, a pointer of the base class can always refer to the object of the derived class.
The image shows that a pointer of the person class when refers to the object of the Student class, the pointer can only access the public interface of the base class.
Output:-
Now, regardless of the actuality that the pointer has reference to the derived class object, all the additional data of the derived class will still be inaccessible by the pointer, which means this personPointer can only have access to the public interface of the Base class.
personPointer->getGrades(); // will cause error: ‘class Person’ has no member named ‘getGrades’
3. Reference Variable of Base Class
The object of the derived class can also be pointed by the Reference of type "Reference of the base class". The situation will remain equivalent to the last condition, it also can only address the generalized part of the object. The reference variable is just an alternative name or alias for the existing variable and it is created by writing & preceding the reference name.
The image shows that when a Reference type variable of the base class references the Student object, it can only access the common properties.
Output:-
Note: The major difference is reference must be initialized at the time of creation only but the pointer can be initialized at any time.
Person &baseReference; baseReference = s1; //Will cause error: expected initializer before ‘baseReference’
Here additional point to notice is although the base reference is an alias to the Student object (s1) but still we can't assign it to some other Student object.
Function Calls
The implicit type conversion also happens at the time of function call, the parameters are being converted to the type of argument.
Digression: Here is a simple example to illustrate this,
Output :
The result came out of expectations because the inbuilt functionality of type conversion in the function call chopped the greater number to make it an integer.
At the instance of the moment when the derived class object i.e. Student Object is being passed to the function, it will be implicitly converted to the Person Type.
Output:-
Note: The reverse assignment is not possible in any of the implicit type conversions.
Explicit Type Conversions
This happens when the programmer explicitly specifies the type conversions, now although the programmer is independent to write code for this type conversion, still there emerges a runtime check to verify whether the explicit conversion which has been specified is possible or not.
The Person as a Base class and Student as a derived class will be used here also.
There are two types of Explicit Casting.
1. Upcast
We can upcast the derived class pointer to the base class pointer. It is also considered to be safer because there is no data loss and no unexpected outcomes due to any uncertainty. After upcasting, the pointer can access the public interface of the base class because the derived class pointer will now be treated as the base class pointer.
The static cast type casts any expression into the desired type and then returns it. Syntax:
Code:
Output:-
Here you can notice everything is the same as the implicit conversion as we were storing the reference of the derived class object in the base class pointer. Now the difference is, due to explicit type upcasting, the personPointer now can also access the public interface of Student Class. If we add these two more lines in the main function, the output will be as following.
Output:-
2. Downcast
The casting of base class pointer to the derived class pointer is called as downcast. Without Explicit Type, the downcasting will not be allowed.
In this example, although the Student Object is being pointed by the person pointer but still due to downcasting we can access the data members and methods of students.
Output:-
Note : This type casting is not always safe because it will introduce some kind of ambiguity in code in a few cases.
For example, suppose the personPointer does not contain the address of the student object and the type cast studentPointer tries to access the data members of the student object. In that case, it will cause some logical problems.
The output is not clear in this case, and that's a kind of huge problem.
To avoid this problem the dynamic_cast is used when the class is in polymorphic form, so that compiler can decide during runtime whether it is safe to downcast or not.
Conclusion
-
The implicit conversion takes place in the assignment of a derived class object to the base class, derived class pointer to base class pointer, and derived class reference to the base class reference. Also, same for the function calls.
-
The explicitly conversion happens according to static cast which can cast the derived class pointer to the base class pointer and vice versa.
-
Upcast is the casting of the base class pointer(which contains the address of the derived class) to the derived class pointer, in this way, the type casted pointer becomes able to access private members of the derived class.
-
Downcast is the process to cast the base class pointer to the derived class pointer, this doesn't consider as safe because after doing so, the base class pointer can access the private members of the derived class which shouldn't be permitted.
-
To ensure whether it is safe or not to downcast, the dynamic cast is being used when the class is in polymorphic form.