2010-07-19 4 views
0

그래서 나는 prata의 C++ 입문서를 마무리하고 있습니다. RTTI를 사용하고 있습니다. 그는 다운 캐스팅 라인을 보여 주었고 잘못되었다고 말했지만 더 좋은 예를보고 싶습니다.포인터 다운 캐스트/상속에 대해서

class Grand 
{ 
private: 
    int hold; 
public: 
    Grand(int h=0) : hold(h) {} 
    virtual void Speak() const { cout << "I am a grand class\n";} 
    virtual int Value() const {return hold; } 
    void Gah() const {cout << "ok" << endl;} 
}; 

class Superb : public Grand 
{ 
public: 
    Superb(int h = 0) : Grand(h){} 
    void Speak() const {cout << "I am a superb class!!\n";} 
    virtual void Say() const 
    { cout << "I hold the superb value of " << Value() << "!\n";} 
    void Sah() const { cout << "Noak" << endl;} 
}; 

class Magnificent : public Superb 
{ 
private: 
    char ch; 
public: 
    int hour; 
    Magnificent(int h = 0, char c = 'A') : Superb (h), ch(c){} 
    void Speak() const {cout << "I am a magnificent class!!!\n";} 
    void Say() const {cout << "I hold the character " << ch << 
     "and the integer " << Value() << "!\n";} 
    void Mah() const {cout << "Ok" << endl;} 
}; 


Grand * GetOne(); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    /* 
    srand(time(0)); 
    Grand * pg; 
    Superb * ps; 
    */ 

    Grand * pg = new Grand; 
    Grand * ps = new Superb; 
    Grand * pm = new Magnificent; 

    Magnificent * ps2 = (Magnificent *)pg; 

    ps2->Gah(); 

    cout << ps2->hour << endl; 

    system("pause"); 
} 

위와 같이 전체적으로 완료되지 않은 파생물에 기초를 캐스팅합니다. 그러나이 예제에서는 무엇이 실제로 제한되어 있습니까? 내가 Pg를 캐스팅 할 때, 나는 여전히 ps2를 통해 모든 웅장한/웅장한/훌륭한 속성과 메소드에 액세스 할 수 있습니다. 즉, 여기서 아무것도 실패하지 않습니다. 누구든지 나에게 예제를 주거나 코드에 무언가를 추가하여 파생 된 부분에 기반을 할당하는 것이 어떻게 엉망이되는지 명확히 보여 줄 수 있습니까?

답변

2

C 스타일의 캐스트는 사용하지 마십시오.
안전하지 않습니다. C++은 새로운 4를 발표했다 당신이 찾고있는 하나입니다 캐스트

Magnificent * ps2 = dynamic_cast<Magnificent*>(pg); // If pg is a Magnificent 
                // (or is a super class of 
                // Magnificent) it works fine. 
// If pg is not a Magnificent (in this case) it will return NULL. 

당신이 모든 규칙을 무시하고있는 컴파일러 (그에게 일을하도록 컴파일러에 이야기되는 C 스타일 캐스트를 사용

> < dynamic_cast는 행복하게 할 수 있습니다.) 당신이하는 일이 어떤 의미인지 확인하기위한 검사가 없습니다.

C++ 스타일의 캐스트는 훨씬 더 제한적이며 각각은 특정 캐스팅 범위를 수행합니다. dynamic_cast는 클래스 계층을 위아래로 캐스팅하는 데 사용됩니다.

0

단순히 ps2->hour에 값을 설정하여, 당신은 메모리를 오버런됩니다 - PS2가 (더 클래스 변수가 같은) Magnificent 예를 들면 충분하지 않은 Grand 인스턴스를 저장하기에 충분히 할당되었다.


- Grand 개체의 배열을 할당하십시오.
- 뭔가
hold의 설정 값 - 주조함으로써, 다른 값
hour의 설정 값 - 모든 요소
에 대한 hold의 인쇄 값 - 어떤 일이 발생을 참조하십시오 ... 그것은으로 깰 수있을

0

곧 파생 클래스의 데이터 멤버을 실제로 사용하는 파생 클래스에서 구현 된 가상 메서드를 호출 할 때. 지금 당장 당신은 행운이 있습니다. Gah 멤버 함수는 아무런 데이터도 건드리지 않습니다.

struct base 
{ 
    virtual ~base() {} 
    virtual void print() const { std::cout << "base" << std::endl; } 
}; 

struct second_base // :) 
{ 
    virtual ~second_base() {} 
    virtual void second_print() const { std::cout << second << std::endl; 
}; 

class derived: second_base, public base 
{ 
    std::string name_; 

public: 

    explicit derived(const std::string& n) : name_(n) {} 

    virtual void print() const 
    { 
     std::cout << "derived: " << name_ << std::endl; 
    } 
}; 

base* pbase(new base); 
derived* pderived = (derived*)pbase; // C-cast will allow this 

pderived->print(); // BOOM! 

이 처리의 RTTI 방법은 당신이 잘못된 서브 클래스로 캐스팅 할 때 0을 반환 dynamic_cast입니다 :

여기 정말 ++ C-스타일 C에서 캐스트의 위험을 보여주는, 실패 예입니다 :

base* pbad(new base); 
base* pgood(new derived("humppa")); 

derived* pfails(dynamic_cast<derived*>(pbad)); 
derived* pworks(dynamic_cast<derived*>(pgood)); 

if (pfails) pfails->print(); // no cookie 
if (pworks) pworks->print(); // prints "derived: humppa" 

연구 C++ casts 연구 C 캐스트 대신 사용하십시오. 항상!

+0

좋아, 지금은 이해하지만 위의 예제는 파생 된 것 대신 기본 인쇄를 실행했습니다 ... 비록 가상 기능이지만 ... – Ilya

+0

예, 게시 후 알게되었습니다. 'base'가 첫 번째 기본 클래스가 아닌 다중 상속 예제를 업데이트했습니다. –