×
>
<

C++ Programming

C++ Upcasting And Downcasting | CrackEase

Upcasting and DownCasting in C++

What is Upcasting and Downcasting in C++

In C++ you can use pointers or references to relate parent (base) and child (derived) classes using "is-a" relationships. Two common conversions between base and derived are:

  • Upcasting — converting a derived type to a base type
  • Downcasting — converting a base type to a derived type

Upcasting

Upcasting treats a derived-class object as if it were an object of the base class. Upcast is safe and implicit when using pointers or references.

Way 1 — pointer upcast
Example
  
Parent* parentPtr;        // Parent class pointer 
Child  childObj;         // Child class object
parentPtr = &childObj;   // implicit upcast: Child* → Parent*
  
Way 2 — reference upcast

Reference upcast is also implicit:

Example
  
Child childObj;
Parent &parentRef = childObj; // implicit upcast: Child& → Parent&
  

Facts

  • The actual object does not change; only the view/access type changes.
  • Through the base pointer/reference you can access only base-class members (unless functions are virtual).
  
#include <iostream>
using namespace std;

// Parent class
class Parent
{
public:
    virtual ~Parent() = default; // virtual destructor for safe polymorphism
    virtual void show()
    {
        cout << "Parent::show()" << endl;
    }
};

// Child class
class Child : public Parent
{
public:
    void show() override
    {
        cout << "Child::show()" << endl;
    }

    void childOnly()
    {
        cout << "Child-specific method" << endl;
    }
};

int main()
{
    Parent *parent_object;
    Child child_object;
    parent_object = &child_object;   // upcast (implicit)

    // Calls Child::show because show() is virtual (runtime polymorphism)
    parent_object->show();

    // parent_object->childOnly(); // Error: not accessible via Parent*
    return 0;
}
  
Output
Child::show()
Downcasting

Downcasting converts a base pointer/reference back to a derived type. This cannot be done implicitly and must be explicit. Prefer dynamic_cast for safety when RTTI is available; it returns nullptr (for pointers) on failure.

Unsafe C-style cast (not recommended)
  
#include <iostream>
using namespace std;

class Parent { public: virtual ~Parent() = default; };
class Child : public Parent {
public:
    void onlyChild() { cout << "Child method\n"; }
};

int main()
{
    Parent p;
    Parent *pp = &p;

    // Forceful cast — undefined behavior if pp does not actually point to Child
    Child *cp = (Child*)pp;
    cp->onlyChild(); // UB if pp is not pointing to a Child object
    return 0;
}
  
Safe downcast with dynamic_cast (recommended)
  
#include <iostream>
using namespace std;

class Parent { public: virtual ~Parent() = default; };
class Child : public Parent {
public:
    void onlyChild() { cout << "Child method\\n"; }
};

int main()
{
    Parent *p = new Child(); // actually points to Child
    Child *c = dynamic_cast(p); // safe downcast

    if (c) {
        c->onlyChild(); // OK
    } else {
        cout << "Downcast failed" << endl;
    }

    delete p;
    return 0;
}
  
Output
Child method

  • Use dynamic_cast when you are not sure about the object's dynamic type. It prevents undefined behavior by returning nullptr on pointer casts that fail.
  • For references, dynamic_cast<Derived&>(baseRef) throws std::bad_cast on failure.
  • C-style casts or static_cast can succeed but are unsafe unless you are certain of the actual type.

Footer Content | CrackEase