C++ casting
Usages
- C++ casting supports checking casting is correct or not, removing constant, and so on
Explain
C++ has 4 types of casting, static, dynamic, reinterpret and const.
Static Cast
Static cast is widely used for common usage. It can change a data type of a variable to what a developer wants if it does not violate. The violation is checked at compile time. Code 1 show how to use it.
// 01_C_testStaticCast.cpp
#include <iostream>
using namespace std;
class BaseClass
{
private:
string name;
public:
BaseClass(string _name)
: name(_name)
{}
void printName()
{
cout << name << endl;
}
};
class DerivedClass : public BaseClass
{
int age;
public:
DerivedClass(string _name, int _age)
: BaseClass(_name),
age(_age)
{}
void printAge()
{
cout << age << endl;
}
};
int main()
{
BaseClass* base = new BaseClass("AAA");
BaseClass* derive1 = new DerivedClass("BBB", 20);
base->printName();
derive1->printName();
//derive1->printAge(); // Compile error
// baseClass does not have printAge()
DerivedClass* derive2 = static_cast<DerivedClass*>(derive1);
derive2->printAge();
return 0;
}
// Compile: clang++ -std=c++14
// -o 01_C_testStaticCast 01_C_testStaticCast.cpp
AAA
BBB
20
Derive1 could not call printAge() at Line 44. Even though the instance is for DerivedClass, it is impossible. The reason is that callable check is done at compile time. The pointer is for BaseClass, then compiler does not allow the pointer to call a function of DerivedClass. To call a function of child, the pointer should be casted to child class pointer. Static_cast helps to translate parent class pointer to child class pointer. After static_cast, printAge() becomes callable.
Dynamic Cast
Dynamic cast is similar to static cast, but its violation check is done at run time. It is usually used for down casting, which converts a parent class to a child class. The code 2 shows how to use it.
// 02_C_testDynamicCast.cpp
#include <iostream>
using namespace std;
class BaseClass {
public:
virtual void printClass(string name)
{
cout << name << " is BassClass" << endl;
}
};
class DerivedClass : public BaseClass
{
public:
void printClass(string name)
{
cout << name << " is DerivedClass" << endl;
}
void childMth(string name)
{
cout << name << " can call child function" << endl;
}
};
void printNull(string var)
{
cout << var << " is null" << endl;
}
int main()
{
BaseClass base;
DerivedClass derive;
BaseClass* _basePtr = &derive;
string name = "base2DerivePtr";
DerivedClass* base2DerivePtr = dynamic_cast<DerivedClass*>(&base);
base2DerivePtr ? base2DerivePtr->printClass(name) : printNull(name);
name = "basePtr";
BaseClass* basePtr = dynamic_cast<BaseClass*>(_basePtr);
basePtr ? basePtr->printClass(name) : printNull(name);
//basePtr->childMth(name); // Compile error
// BaseClass does not have childMth()
name = "derivePtr";
DerivedClass* derivePtr = dynamic_cast<DerivedClass*>(_basePtr);
derivePtr ? derivePtr->printClass(name) : printNull(name);
derivePtr->childMth(name);
name = "baseRef";
BaseClass& baseRef = dynamic_cast<BaseClass&>(*_basePtr);
baseRef.printClass(name);
//baseRef.childMth(name); // Compile error
// BaseClass does not have childMth()
name = "deriveRef";
DerivedClass& deriveRef = dynamic_cast<DerivedClass&>(*_basePtr);
deriveRef.printClass(name);
deriveRef.childMth(name);
return 0;
}
// Compile: clang++ -std=c++14
// -o 02_C_testDynamicCast 02_C_testDynamicCast.cpp
base2DerivePtr is null
basePtr is DerivedClass
derivePtr is DerivedClass
derivePtr can call child function
baseRef is DerivedClass
deriveRef is DerivedClass
deriveRef can call child function
base2DerivePtr is null, because the instance of parent class is not able to cast to child class, then the casting is failed. This is one of pros of dynamic cast. It checks violation at the run time, and if transform is not available, it returns null pointer. The type of _basePtr is BaseClass*, but its real instance is DerivedClass. Therefore, _basePtr is casted to BaseClass and DerivedClass, but its print() tell us it is DerivedClass. By using dynamic cast, it is possible to call printNum() of DerivedClass from the instance of DerviedClass with the pointer of BaseClass.
Reinterpret Cast
Reinterpret cast is unreasonable cast, like C's cast. It can change a data type to whatever a developer wants. Therefore, be careful. Code 3 shows how to use it.
// 03_C_testReinterpretCast.cpp
#include <iostream>
using namespace std;
class BaseClass
{
public:
void printClass(string name)
{
cout << name << " is BassClass" << endl;
}
};
int main()
{
string name = "bastPtr";
BaseClass* basePtr = new BaseClass{};
long address = reinterpret_cast<long>(&basePtr);
cout << "Address is " << address << endl;
basePtr = reinterpret_cast<BaseClass*>(address);
basePtr->printClass(name);
return 0;
}
// Compile: clang++ -std=c++14
// -o 03_C_testReinterpretCast 03_C_testReinterpretCast.cpp
Address is 140737261789864
bastPtr is BassClass
Const cast
Const cast is used to remove const attribute from a variable. Therefore, it is very useful. Code 4 shows how to use it.
// 04_C_testConstCast.cpp
#include <iostream>
using namespace std;
class BaseClass
{
public:
BaseClass(string _name, int _age)
: name(_name)
, age(_age)
{}
const string getName()
{
return name;
}
const int getAge()
{
return age;
}
void print(string instance)
{
cout << instance << " Name: " << name << ", Age: " << age << endl;
}
private:
const string name;
const int age;
};
int main()
{
BaseClass baseSrc{"AAA", 20};
const string name = baseSrc.getName();
const int age = baseSrc.getAge();
//name = "BBB";
string* tempName = const_cast<string*>(&name);
*tempName = "BBB";
//age = 30;
int* tempAge = const_cast<int*>(&age);
*tempAge = 30;
BaseClass baseDest(*tempName, *tempAge);
baseSrc.print("Source");
baseDest.print("Destination");
return 0;
}
// Compile: clang++ -std=c++14
// -o 04_C_testConstCast 04_C_testConstCast.cpp
Source Name: AAA, Age: 20
Destination Name: BBB, Age: 30
Const cast makes another memory space for non const variable. As a result, the contents of baseSrc and baseDest are different.
Summary
- Static cast: Normal casting. It checks violation at compile time.
- Dynamic cast: Normally used for down cast. It checks violation at run time.
- Reinterpret cast: Dangerous cast. It can change a variable to any type.
- Const cast: It removes const attribute. It makes another memory space.
COMMENTS