'static_cast derived this object to base class in C++
When reading Item 27 Minimize casting in Effective C++, it says do not try to use static_cast to cast *this in derived class to base class. It because static_cast<Base>(*this) will create a temporary object of Base class. I tried an example as follows, however, it always output 10 using different compilers such as clang 3.8 and gcc 4.9, 5.3.
Am I wrong?
#include <iostream>
class A {
public:
int a;
virtual void foo() {std::cout << a << std::endl;}
};
class B : public A {
public:
int b;
void foo () { static_cast<A>(*this).foo();}
};
int main () {
B b;
b.a = 10;
b.foo();
return 0;
}
The question is why static_cast will create a temporary object.
Solution 1:[1]
A more meaningful example would be this one:
#include <iostream>
class A {
public:
virtual void foo() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
virtual void foo() { std::cout << "B" << std::endl; }
void bar () { static_cast<A>(*this).foo(); }
};
int main () {
B b;
b.bar();
}
I'd expect bar to print B, for foo is an overridden method. It prints A instead.
Well, that's right from the the point of view of the language, not so good from the point of view of the developer that was expecting a completely different result.
It works if you use instead the following class:
class B : public A {
public:
virtual void foo() { std::cout << "B" << std::endl; }
void bar () { static_cast<A*>(this)->foo(); }
};
Also the following one works as expected (added for the sake of clarity, thanks to @MORTAL in the comments):
class B : public A {
public:
virtual void foo() { std::cout << "B" << std::endl; }
void bar () { static_cast<A&>(*this).foo(); }
};
Anyway, the problem you are facing with is named slicing.
That's why using static_cast<A>(*this) is discouraged if you don't know what you are doing.
See here for further details.
Solution 2:[2]
The problem with your code is that you do not modify the value of A's a variable, thus you do not see a change between the values of the two instances.
Add the following copy constructor for A:
A() = default; // so that it still exists...
A(A const& other)
: a(other.a + 1) // initialise to a value definitely differing...
{ }
Now you should see 11 instead, confirming the statement...
Solution 3:[3]
First of all you don't have to cast Derived -> Base because it happens automatically. And yes, static_cast will create an object of type which you casting to. In your case to enable polymorphism you can use either references or pointers:
int main(){
B b;
A &a = b; // no explicit cast needed
a.foo(); // will call B::foo
//OR
B *bPtr = new B;
A *aPtr = bPtr; // no explicit cast needed
aPtr->foo(); // same as above
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Community |
| Solution 2 | Aconcagua |
| Solution 3 | LibertyPaul |
