Please help me to understand the following issue.
Look at the code example below:
#include <iostream>
class Shape {
public:
virtual wchar_t *GetName() { return L"Shape"; }
};
class Circle: public Shape {
public:
wchar_t *GetName() { return L"Circle"; }
double GetRadius() { return 100.; }
};
int wmain() {
using namespace std;
auto_ptr<Shape> aS;
auto_ptr<Circle> aC(new Circle);
aS = aC;
wcout << aS->GetName() << L'\t' << static_cast<auto_ptr<Circle>>(aS)->GetRadius() << endl;
return 0;
}
Why I am not allowed to do this:
static_cast<auto_ptr<Circle>>(aS)->GetRadius()
Compiler (MSVCPP 11):
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory(911): error C2440: 'initializing' : cannot convert from 'Shape *' to 'Circle *'
1> Cast from base to derived requires dynamic_cast or static_cast
auto_ptrdoesn’t behave the same way as a pointer in this respect. There are special rules in the language to allowShape*to be static_cast toCircle*whenCirclederives fromShape. The downcast is not entirely type-safe, since it relies on the user to provide a pointer value that actually does point to theShapebase class sub-object of aCircle, but the standard allows it for convenience.auto_ptris “just” a library class, and has no equivalent conversion.Even if you could do it, it would often go wrong. When you copy an
auto_ptr, the original loses ownership of the resource. Yourstatic_castwould copy theauto_ptrto a temporary, and soaSwould be reset and the resource would be destroyed when the temporary is (at the end of the expression). In your example that’s fine, since it’s going to be destroyed atreturnanyway, but generally speaking you don’t want to copyauto_ptrexcept at a function call parameter or return value, to indicate transfer of ownership from caller to callee, or vice versa.What you can do instead is
static_cast<Circle*>(aS.get())->GetRadius(), or better yet restructure your code to avoid the need for a downcast. If you know that your object is aCircle, keep it in anauto_ptr<Circle>[*]. If you keep it in anauto_ptr<Shape>, then don’t rely on it being aCircle.[*] Or, if your implementation provides them, a better smart pointer such as
unique_ptr,scoped_ptrorshared_ptr. Even if your implementation doesn’t provide them, there’s Boost.