1

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;
}
5
  • 4
    Why do you expect a compiler error? Commented Jun 27, 2019 at 16:17
  • 2
    No, the compiler doesn't catch undefined behavior with errors. BTW, you could check the correctness with a dynamic_cast<Derived*> at runtime. Commented Jun 27, 2019 at 16:18
  • I guess the OP wants to ask about slicing Commented Jun 27, 2019 at 16:22
  • 1
    @oblivion I can't see why. There's no slicing in this whatsoever, just blatant casting leading to later undefined behavior. Commented Jun 27, 2019 at 16:23
  • 2
    (Derived*)BaseObj is a c-style cast and sloppy speaking it tells the compiler: "I am more clever than you, do not bother me with warnings or errors". Don't use it when you want the compiler to help you with warnings / errors Commented Jun 27, 2019 at 16:26

3 Answers 3

2

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;
}
Sign up to request clarification or add additional context in comments.

Comments

1
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.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.