2011-12-20 2 views
0

다음 문제를 이해하도록 도와주세요. 아래의 코드 예제에서auto_ptr 캐스팅 auto_ptr <Base><Derived>

봐 :

나는이 할 수 없습니다입니다 왜
#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; 
} 

:

static_cast<auto_ptr<Circle>>(aS)->GetRadius() 

컴파일러 (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 
+4

@Truncheon : 의도적으로 _trolling_ 있습니까? 몇 달 후 나는이 느낌이 들지 않았다. 당신의 의견은 "우리가 의견을 줄이면 좋겠다"라는 또 다른 사례이다. – sbi

+2

너무 형편 없기 때문에 의견을 투표 할 수 없습니다.메모리 관리가 포인터를 래핑하는 객체에 의해 처리 될 수 있다고해도 std :: auto_ptrs가 항상 최선의 대안이 아니라는 사실에 나는 당신과 동의한다. 그러면 개발자는 포인터가 매달 리는 것에 대해 생각할 필요없이 자신이 해결하고있는 실제 문제에 집중할 수 있습니다. –

+0

@sbi 우리는 비슷하게 생각합니다. (참고로,이 글을 새로 고치지 않았기 때문에 내 글을 쓸 때 귀하의 코멘트를 보지 못했습니다) –

답변

5

auto_ptr 아무튼 이 점에서 포인터와 같은 방식으로 동작합니다. 언어에 Shape*이 인 static_cast가되도록 허용하는 특수 규칙이 있습니다. CircleShape에서 파생됩니다. 다운 캐스트는 실제로 사용자가 CircleShape 기본 클래스 하위 객체를 가리키는 포인터 값을 제공하는 데 의존하기 때문에 전체적으로 유형에 안전하지는 않지만 표준을 사용하면 편리합니다. auto_ptr은 "그냥"라이브러리 클래스이며 이에 상응하는 변환이 없습니다.

할 수 있다고해도 종종 잘못 될 것입니다. auto_ptr을 복사하면 원본이 리소스 소유권을 잃습니다. static_castauto_ptr을 임시로 복사하므로 aS이 재설정되고 임시 (표현식 끝 부분) 일 때 리소스가 삭제됩니다. 어쨌든 return에서 소멸 될 것이기 때문에 당신의 예제에서는 괜찮을 지 모르지만 일반적으로 함수 호출 매개 변수 또는 반환 값을 제외하고는 auto_ptr을 복사하지 않으므로 호출자에서 호출 수신자로 소유권이 이전되었음을 나타내거나 반대의 경우도 마찬가지입니다. .

대신 수행 할 수있는 작업은 static_cast<Circle*>(aS.get())->GetRadius()이거나 다운 캐스트가 필요하지 않도록 코드를 재구성하는 것이 좋습니다. 개체가 Circle 인 경우 auto_ptr<Circle> [*]에 보관하십시오. auto_ptr<Shape>에 보관하는 경우 Circle에 의존하지 마십시오.

[*] 또는 구현에서 제공하는 경우 unique_ptr, scoped_ptr 또는 shared_ptr과 같은 스마트 포인터가 더 우수합니다. 비록 당신의 구현이 그들을 제공하지 않는다고해도, Boost가 있습니다.

+0

매우 명확하다. 감사. 그러나 auto_ptr을 사용할 때 파생 된 base (static_cast)를 캐스팅하려면 어떻게해야합니까? 나는 그것이 틀릴 수도 있다는 것을 알고 있지만이 상황에서 나는 기본 클래스 객체에 대한 포인터가 실제로 파생 된 객체를 가리킨다는 것을 안다. – DaddyM

+0

@DaddyM 내 게시물을 참조하십시오. 입력 할 때 약간 느립니다. –

+0

refp의 대답과 똑같은 코드를 보지 않고 정확히 제작 했으므로 아마 맞을 것입니다. –

3

std::auto_ptr<T>은 클래스의 다른 인스턴스로 초기화 할 때 내부 포인터의 소유권을 갖기 때문에 확실히 캐스트를 수행하고 싶지는 않습니다.

aS은 포인터를 풀어 std::cout 문 끝에 개체를 소멸시킵니다. 개체 포인터는 이제 임시로 소유되기 때문에 new Circle 개체는 소멸됩니다. 대신

당신은 아마 아래와 같은 뭔가를 찾고있다 :

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

또한이 참조로 캐스팅 할 수 있습니다, 아래 :

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

감사. 매우 명확하고 건설적인. – DaddyM

관련 문제