Introduction to C++: New Syntax for Type Conversion – Template Conversion Functions

New Syntax for Type Conversion in C++ – Template Conversion Functions

  • C++ supports the C language’s syntax for forced type conversion and has introduced a new method that allows for better control over the conversion process.
  • Upcasting: Converting a subclass to a superclass, where the subclass space is given to a superclass pointer (safe).
  • Downcasting: Converting a superclass to a subclass, where the superclass space is given to a subclass pointer (unsafe, may cause memory overflow).

static_cast

  • Static type conversion.
  • Used for converting pointers or references between base classes and derived classes in a class hierarchy.
class Parent {};
class Son : public Parent { };

// Basic type - supported
int num = static_cast<int>(3.14);
// Upcasting - supported, safe
Parent * p = static_cast<Parent*>(new Son);
// Downcasting - supported, unsafe
Son * p2 = static_cast<Son*>(new Parent);
// Unrelated type conversion - not supported

dynamic_cast

  • Dynamic type conversion.
  • Used for upcasting in class hierarchies.
class Parent {};
class Son : public Parent { };

// Upcasting - supported, safe
Parent * p = dynamic_cast<Parent*>(new Son);

// Downcasting - not supported, unsafe
// Basic type - not supported
// Unrelated type conversion - not supported

const_cast

  • Constant conversion.
// Convert a const pointer to a non-const - supported
const int * p;
int * p1 = const_cast<int*>(p);
const int &num = 10;
int &num2 = const_cast<int&>(num);
// Convert a non-const to const - supported
int * p2;
const int * p3 = const_cast<const int*>(p2);
int num3 = 10;
const int &num4 = const_cast<const int&>(num3);

reinterpret_cast

  • Reinterpretation conversion.
  • The least safe type of conversion.
class Parent {};
class Son : public Parent { };
class Other { }

int num = reinterpret_cast<int>(3.14);
// Upcasting - supported, safe
Parent * p = reinterpret_cast<Parent*>(new Son);
// Downcasting - supported, unsafe
Son * p2 = reinterpret_cast<Son*>(new Parent);
// Unrelated type conversion - supported
Parent * p3 = reinterpret_cast<Parent*>(new Other);
// Basic type pointer conversion - supported
float * fp;
int * intp = reinterpret_cast<int*>(fp);

// Basic type - not supported

Exceptions

  • Throwing exceptions, catching exceptions.
  • If an exception thrown is not actively caught, the program will be taken over by the system and stop running.
  • Stack unwinding.
    • When an exception is thrown, all objects constructed on the stack from the entry into the try block until the exception is thrown (throw) will be automatically destructed, in the reverse order of their construction. This process is called stack unwinding.
  • The built-in exception class is the base class for all exceptions. Custom exception classes must inherit from this class and override the what function.
// try {
//     throw "Throwing an exception";
// } catch (ExceptionType1 exceptionValue1) {
//     // Only catch exceptions of matching type
// } catch (ExceptionType2 exceptionValue1) {
//     // Only catch exceptions of matching type
// } catch (...) {
//     // Catch any exception
// }
try {
// throw 1;
// throw 'a';
    throw 1.12f;
} catch (int a) {
cout << a << endl;
} catch (char b) {
cout << b << endl;
} catch (...) {
cout << "Unmatched exception" << endl;
}
  • Exception interface description.
    • Describes which exceptions can be thrown.
    • Exceptions not described will be handled by the system.
    • Functions can throw any type of exception by default.
// Specify throwing specific exceptions
void fn() throw(int, char) {}
try {
    fn(); // Since fn specifies throwing exceptions of type int and char, this try's catch can only catch int and char type exceptions, even if a catch for float is written, it won't catch.
} catch (int a) {
} catch (char a) {
} catch (float a) {
}

// Cannot throw any exceptions
void fn2() throw() {}
  • Lifecycle of exception variables.
    • No need for manual delete.
    • Need to manually delete the pointer to the object receiving the exception.
    • When a normal object receives an exception value, it triggers: exception object construction, copy construction, normal object receiving exception, exception object destruction, normal object destruction.
    • When an object pointer receives an exception value, it triggers: exception object construction, normal object receiving exception, exception object destruction.
    • When an object reference receives an exception value, it triggers: exception object construction, normal object receiving exception, exception object destruction.
// Recommended to use object reference to receive exception values
class MyException : public exception {
string msg;
    public:
        MyException() {}
        MyException(int msg) {
            this->msg = msg;
        }
        virtual const char * what() const throw() // Prevent parent class from throwing standard exceptions before child class
        {
return this->msg.c_str(); // c_str converts string class object to char*
        }
}
try {
    throw MyException('Error message');
} catch (MyException &e) {
cout << e.what() << endl;
}
  • Polymorphism of exceptions.
    • Deriving multiple subclasses of exceptions from a base class exception.
    • Can use base class exceptions to catch subclass exceptions derived from that base class.
  • Common built-in standard exceptions in C++.
    • All have a virtual function what for printing exception information, all subclasses will override this virtual function.
    • exception is the base class for all exceptions.
    • logic_error
    • runtime_error
    • out_of_range
try {
    throw out_of_range('Out of range');
} catch (exception &e) {
cout << e.what() << endl;
}

Leave a Comment