user3225861
user3225861

Reputation: 65

Converting base class pointer to derived class pointer

As shown in the following code i am trying to convert a base class pointer to derived class pointer. I am expecting compiler error from the following code but does not report any error. Also the function "SomeMethod_2" printing value 10.

#include <iostream>

using namespace std;

class Base {
public:
    Base() {
        cout << "Base class constructor\n";
    }

};

class Derived : public Base
{
public:
    int Val;
    Derived() {
        cout << "Derived class constructor\n";
    }
    void SomeMethod(void)
    {
        cout << "SomeMethod\n";

    }
    void SomeMethod_1(void)
    {
        Val = 10;
    }
    void SomeMethod_2(void)
    {
        cout << Val;
    }
};


int main()
{
    Base* BaseObj = new Base();

    Derived* DerivedObj = (Derived*) BaseObj;

    DerivedObj->SomeMethod();    # Expecting compiler error
    DerivedObj->SomeMethod_1();
    DerivedObj->SomeMethod_2();
    return 0;
}

Upvotes: 1

Views: 373

Answers (3)

Boki
Boki

Reputation: 657

You have just executed c-style cast of Base* to Derived*. Function SomeMethod is defined in Derived class and as such its call is legal through Derived*, not an compile time error. Member functions are not part of class instance, but rather they've placed in code segment and member functions invocation for particular instance is possible with hidden this argument. If you have no data members there are even no slicing happened. It is always good idea, after pointer casting to check if what it is cast to, represent an valid pointer. And of course, in c++ we use dynamic_cast for use case like this.

Upvotes: 1

eerorika
eerorika

Reputation: 238291

Derived* DerivedObj ....
DerivedObj->SomeMethod();    # Expecting compiler error

I am expecting compiler error

There's no reason to expect a compiler error here. DerivedObj is a pointer to Derived which has a member function SomeMethod and therefore the function call is well-formed, and compiler is required to succesfully compile it.

Now, whether the behaviour of indirecting through the pointer DerivedObj and calling a member function is well defined depends on whether the pointer is valid. It is not valid in this case, and therefore the behaviour of the program is undefined.

Also the function "SomeMethod_2" printing value 10.

This is an example of undefined behaviour.

Upvotes: 1

aschepler
aschepler

Reputation: 72271

A cast, especially a C-style cast, tells the compiler to shut up about many errors and warnings, and that you promise you know what you're doing, at your own risk.

Using a pointer which does not point at an object of that type is in most cases Undefined Behavior. Undefined Behavior is just that - there are no requirements about what could happen, so you MIGHT get a compiler error or runtime error. Or you might have it seem to "work" (whatever that might mean), or something entirely unexpected.

As far as what's actually going on in your particular case, the functions are most likely using adjacent memory that does not belong to *BaseObj to store the int, but this happened not to matter afterward. If you had remembered to delete the object, though, there's a chance you would run into a problem at that point, since the overwritten memory may have been used by the heap memory management functions.

Note that if Base had at least one virtual function (like the destructor), and if you used the safer dynamic_cast instead of the least safe C-style cast, then the result of the cast would be a null pointer, since dynamic_cast does a check for whether the object actually is of that type.

class Base {
public:
    Base() {
        cout << "Base class constructor\n";
    }
    virtual ~Base() = default;
};

// ...

int main()
{
    Base* BaseObj = new Base();

    Derived* DerivedObj = dynamic_cast<Derived*>(BaseObj);

    if (DerivedObj) {
        DerivedObj->SomeMethod();
        DerivedObj->SomeMethod_1();
        DerivedObj->SomeMethod_2();
    } else {
        std::cout << "Not a Derived\n";
    }

    delete BaseObj; // Don't forget to match every "new" with a "delete".
    return 0;
}

Upvotes: 2

Related Questions