Reputation: 65
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
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
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
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