2012-04-02 2 views
10

그래, Base이 다형성이 아니지만 내 문제가 이것에 관한 것이 아니라면, dynamic_cast을 사용한 다운 캐스트는 컴파일 할 수 없다는 것을 알고 있습니다.Base에서 Derived의`dynamic_cast`

class Base { 
    public: 
     virtual void bar() 
     { 
      cout << "bar\n"; 
     } 
}; 

class Derived: public Base { 
    public: 
     void foo() 
     { 
      cout << "foo\n"; 
     } 
}; 

int main() 
{ 
    Base *pb; 
    Derived *pd; 

    pb = new Derived; //Base* points to a Derived object 
    pd = dynamic_cast<Derived*>(pb); 
    pd->foo(); //outputs foo 

    pb = new Base; //Base* points to a Base object 
    pd = dynamic_cast<Derived*>(pb); 
    pd->foo(); //outputs foo, too. Why? 
} 

나는 pb = new Derived;pb 실제로 Derived 객체를 가리키는 경우 힙에있다 생각했다. pd = dynamic_cast<Derived*>(pb); 이후에 pdDerived 개체를 가리키고 있으므로 pd->foo()은 정상이어야합니다.

그러나, pd = dynamic_cast<Derived*>(pb); 후 다음 힙에서 Base 객체에 어떤 pbpb = new Base;을 때, 어떻게 pd->foo() 작품 수 있을까? dynamic_cast을 개체를 Derived 개체로 전환 했습니까?

답변

17

C++에서 클래스의 각 인스턴스에는 고유 한 버전의 데이터 유형이 있지만 모든 클래스는 메모리에서 같은 기능을 공유합니다 (인라인 함수 제외).

pd->foo(); 

당신은 기본적으로 메모리 기능이며이 어디 컴파일러가 알고 Derived::foo을 요구하고있다 : 귀하의 경우에, 당신은 뭔가처럼 말할 때. 문제는 pd에 전혀 의존하지 않는다는 것입니다.

class Derived : public Base { 
    private: 
     int a; 

    public: 
     Derived() { a = 100; } 

     void foo() { 
      std::cout<<a<<std::endl; 
     } 
}; 

그런 다음, pd->foo()이 분할 오류가 발생할 것이다 : 그러나,이 같은 일을했다. 여기서 동적 캐스트가 실패했으며 Derived::foo이 호출되면 0this 개체로 전달됩니다. 위의 경우에는 this 개체가 사용되지 않았으므로 문제가되지 않았습니다. 그러나 두 번째 경우에는 사용되어 Segmentation 오류가 발생합니다.

+0

'pd-> foo();'라고하면'foo()'는'pd'가'NULL'이든 상관없이 호출됩니다. – Alcott

+0

@Alcott yes. 그러나 'this' 매개 변수는 NULL로 전달됩니다 (즉,'pd'의 값). 따라서 Rohan의 예에서'a'에 액세스하여 역 참조 해제 할 때 예상되는 충돌이 발생합니다. – littleadv

+1

이것은 주로 컴파일러에 의존적이며 @Luchian Grigore가 언급했듯이 모든 일이 발생할 수 있습니다. 그래서, 대부분의 경우, 그렇습니다. 그러나 그것은 당신이 의지 할 수없는 것입니다. –

7

foo에는 this에 액세스하지 않습니다.이 경우 NULL이어야합니다. 그것은 캐스트가 완료 될 수 없을 때 dynamic_cast이 반환하는 것입니다.

기본적으로 여기에 "정의되지 않은 동작"영역이 있습니다.

+0

참고로 올바른 답변이므로 +1했습니다. * 그러나 * 아직도이 같은 것이 행운이라는 것을 알지 못합니다. 프로그램이 있어야 할 때 충돌을 일으키지 않기 때문에 추적하기 어려운 버그로 실행할 수 있습니다. –

+1

@LuchianGrigore [행운] (http://en.wiktionary.org/wiki/luck#Noun) 1. 우연히 우연히 발생하는 일, 우연한 사건. – Potatoswatter

6

정의되지 않은 동작이 발생하고 있습니다. 반환 유형 dynamic_cast을 확인해야합니다.

pd = dynamic_cast<Derived*>(pb); 

이 값은 null을 반환하고 NULL 포인터에서 함수를 호출합니다. 아무거나 일어날 수있다.

+0

그러나'pd == NULL'이라면, 왜 런타임 에러가 없습니까? – Alcott

+0

@Alcott 정의되지 않은 동작입니다. 아무거나 일어날 수있다. –

+1

@Alcott 기술적으로 Luchian의 대답은 정확합니다. 그러나 실제적으로 이유는 컴파일러 개발자가 복잡하고 성능이 많이 드는 실행 시간 검사를 구현하는 대신 허용 된 것처럼 컴파일러 개발자가이를 무시하는 것이 더 간단하기 때문입니다 (표준에서는 이러한 경우 수행 할 작업을 정의하지 않기 때문에). 모든 포인터 액세스. 따라서 어떤 일이 일어나고 - 어떤 일이 일어나고 올바른 것이 있습니다. – littleadv

1

캐스트를 사용하기 전에 캐스트가 성공했는지 항상 확인하는 것이 좋습니다. 캐스팅 사용의 이점을 짐작할 수 있습니다. 성공 여부를 확인할 수 있습니다.

pd = dynamic_cast<Derived*>(pb); 
if(pd!=NULL) 
    pd->foo(); 

캐스팅에 실패하면 pd 값이 NULL입니다. 가치가 없다면 pd을 사용하지 마십시오. 그런 다음 참조 만하십시오.

관련 문제