Cast auto_ptr <Base> to auto_ptr <Derived>

Please help me understand the following problem.

Check out the sample code 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 
0
source share
2 answers

auto_ptr does not behave the same as a pointer in this regard. There are special rules in the language that allow Shape* be static_cast to Circle* when Circle comes from Shape . Deferred is not completely type safe because it relies on the user to provide a pointer value that actually points to a sub-object of the Shape base class for Circle , but the standard allows this for convenience. auto_ptr is a "simple" library class and does not have an equivalent conversion.

Even if you could do it, this is often a mistake. When you copy auto_ptr , the original loses ownership of the resource. Your static_cast would copy auto_ptr to temporary, and therefore aS would be reset, and the resource would be destroyed when temporary (at the end of the expression). In your example, this is fine, since it will be destroyed in return anyway, but generally speaking, you do not want to copy auto_ptr except for the function call parameter or return value to indicate the transfer of ownership from the caller to the caller, or vice versa.

Instead, you can do static_cast<Circle*>(aS.get())->GetRadius() or better restructure your code to avoid having to drag and drop. If you know your object is Circle , save it in auto_ptr<Circle> [*]. If you save it in auto_ptr<Shape> , then do not rely on it as a Circle .

[*] Or, if your implementation provides them, a better smart pointer such as unique_ptr , scoped_ptr or shared_ptr . Even if your implementation does not provide them, there is Boost.

+5
source

You, of course, do not want to do this, since std::auto_ptr<T> takes responsibility for the internal pointer when initializing with another instance of the class.

aS , therefore, will lose the pointer, and your new Circle object will be destroyed at the end of the std::cout statement, since the object pointer now belongs to the temporary one.

Instead, you're probably looking for something like the following:

 cout << ... << static_cast<Circle*>(aS.get ())->GetRadius() << endl; 

You can also use it for reference, as shown below:

 cout << ... << static_cast<Circle&> (*aS).GetRadius () << endl; 
+3
source

Source: https://habr.com/ru/post/1387264/


All Articles