2014-05-19 5 views
-6
#include <iostream> 
using namespace std; 
class Person 
{ 
public: 
     void P(){ cout << "Person P" << endl; } 
     virtual void Print(){ cout << "Person Print" << endl; } 
     Person(){ cout << "Constructor Person" << endl; } 
     virtual ~Person(){ cout << "Dectructor Person" << endl; } 
}; 
class Developer : public Person 
{ 
public: 
     void Pi() { cout << "Developer Pi" << endl; } 
     void Print() override 
     { 
       cout << "Developer Print" << endl; 
     } 
     Developer(){ cout << "Constructor Develoeper" << endl; } 
     ~Developer(){ cout << "Dectructor Develoer" << endl; } 
}; 
int main() 
{ 
     Person *p = new Person(); 
     Developer* d = dynamic_cast<Developer*>(p); 
     d->Pi(); 

     delete p; 
     delete d; 
    return 0; 
} 

출력 :파생 클래스의 방법

Constructor Person 
Developer Pi 
Dectructor Person 

왜 내가 Developer의 기능 Pi 호출 할 수 있습니다?

Developer 님의 생성자 없이는 Pi을 어떻게 호출 할 수 있습니까?

PiDeveloper 클래스에서만 선언됩니다.

+0

원하는대로 할 수 있지만 ** 정의되지 않은 동작이 발생합니다 ** – Rakib

+0

이것이 UB 인 이유에 대한 매우 철저한 답을보십시오. http://stackoverflow.com/a/2474021/3549027 – dlf

답변

3

수 없습니다. 코드에 정의되지 않은 동작이 있습니다. 나는에 main() 기능을 수정하는 경우 :

int main() 
{ 
    Person *p = new Person(); 
    Developer* d = dynamic_cast<Developer*>(p); 
    assert(d!=0); 
    d->Pi(); 

    delete p; 
    delete d; 
    return 0; 
} 

는 그런 주장 d!=0 트리거됩니다. 이는 dynamic_cast이 실패했음을 나타냅니다. null 포인터에 Developer::Pi을 호출하면 컴파일러를 사용하면 정상적으로 실행됩니다. 왜냐하면 Developer::Pithis을 사용하지 않기 때문일 것입니다.

+1

@irineau, 이것은 OP의 대답이 아닙니다. 놀랍게도'Pi '라고 부르는 코드가 작동한다고 주장하지 않고 질문을하는 이유는 무엇입니까? – Rakib

2

Developer* d = dynamic_cast<Developer*>(p);
당신은 d == nullptr입니다. d->Pi();

당신은 정의되지 않은 동작을 호출 :

방법은 매개 변수로 추가 this을하고 this를 사용하지 않는 한 방법이 경우에 작동하는 것 같다 함수에 일반적으로 해당 있습니다.

0

dynamic_cast가 원인입니다. 인스턴스의 변수를 언급하지 않으므로 실패하지 않습니다.

가상 메서드에 액세스하거나 개체에 저장된 내용에 액세스하면 액세스 위반이 발생합니다.

0

d가 개발자 클래스의 개체에 대한 포인터임을 나타내면 컴파일러에 힌트를 제공합니다. 또한 void Pi()가 가상이 아닌 것으로 선언 했으므로 컴파일러는 초기 바인딩 (컴파일 타임)을 사용했습니다. 즉, 호출되는 함수의 주소가 컴파일 중에 고정되어 있고 (가상 메서드와 달리) 평가할 개체가 필요하지 않습니다.

d-> Pi()를 호출하면 사용자와 동일합니다 Pi가 개발자 인스턴스에 대한 포인터를 취하는 Pi (d)를 호출합니다. MFC에는 Validate라고하는 메서드가 있습니다. 포인터가 null이 아닌지 확인하기 위해 매우 동일한 메커니즘을 사용하는 메서드가 있습니다.

표준에 있기 때문에 삭제 d에서 크래시가 발생하지 않지만, null 포인터를 삭제하는 것이 좋으며 아무것도하지 않습니다 (더티 포인터를 삭제하는 것은 어렵습니다).

Pi 메서드 서명에 virtual이라는 단어를 추가하거나 개발자 클래스에 필드를 추가하고 Pi 메서드에서 해당 필드를 수정하십시오. 그러면 차이점을 볼 수 있습니다.)

관련 문제