2012-02-23 3 views
2

나는,이 경우이예외 처리 + 다형성, 예외 방법 경우 나던 작업, 같은 클래스에서 나던 작품은

//A.hpp 
class A{ 
    public: 
     A() {} 
     virtual const char *message() const {return "A ERROR";} 
}; 

//B.hpp 

#include "A.hpp" 

class B:public A { 
    public: 
     B() {} 
     const char *message() const {return "B ERROR";} 
}; 

//main.cpp 
#include "A.hpp" 
#include "B.hpp" 

void foo(const A& a) { 
    /* case 1 */ throw a; /* (or) */ /* case 2 */ throw B(); // LINE 100 
} 

int main() { 

    B b; 
    A &a(b); 
    b.message(); // OUTPUT: B ERROR 

    try { 
     foo(a); 
    } catch (const A& a) { 
    std::cout<<"EXCEPTION CALLED "<<a.message()<<std::endl; 
    } 
    return 0; 
} 

같은 몇 가지 코드를 시도하고있다 : 가 던져를; // a는 B b의 참조입니다. 출력 : 오류

사례 2 : throw B(); // 새로운 B를 만듭니다; 출력 : B 오류

이해가 안 무엇, 당신은 참조로 전달하는 경우, 모든 시간을, 어떤 일관성이 있어야한다

이가지 경우 betweek 일관성이 존재하지 않는 이유, 을 함수 내부에 새로운 변수를 만들면 try 블록에서 호출되고 올바른 가상 메서드가 호출됩니다. 그렇지 않으면 아무도 제어 흐름을 말할 수 없습니다 .... 조언하십시오. ...

답변

5

개체가 던져지기 전에 복사되기 때문입니다.

런타임에서 B의 인스턴스에 foo 점의 a 매개 변수가 무엇 중요한 것은 투사 식의 컴파일시 유형 인 경우에도 마찬가지입니다. 따라서 B의 인스턴스는 복사 생성자 A (BA을 상속하므로 합법적입니다) 및 새 A 인스턴스가 만들어져 throw됩니다.

이유는 컴파일러가 catch 할 수있는 블록이있는 catch 블록이있는 한 예외 개체의 수명을 보장해야한다는 것입니다. 따라서 스택 객체 "스택 가장자리에서 떨어지는"위험을 감수 할 수 없으며 스택 해제 중에 호출 된 일부 소멸자가 힙 객체를 할당 해제 할 수 없습니다.

1

변수를 복사하는 중입니다. foo의 throw a은 실제로 메인에서 a에 대한 참조를 던지지 않으며 사실 a 사본을 던집니다. catch 문에서 참조로 해당 복사본을 잡습니다. foo에서 aA에 대한 참조이므로 복사가 객체를 조각화하고 A이되어 결국 B이라는 사실을 잃게됩니다.

-1

당신이 무엇을 요구하고 있는지 정확히 이해하는 데는 어려움이 있습니다 ... 먼저 "catch"변수에 "a"를 두 번 사용하는 로컬 변수와 동일한 이름을 지정하지 마십시오 다른 것을 나타 내기 위해. 당신은 당신이 참조로 잡을 항목은 푸에 전달 된 A는 생각 될 수 있으며 푸() 나는 무슨 일이 일어나고 있는지 의심

catch (const A& ex) 
{ 
...ex.message()... 
} 

에 캐치를 변경 그냥 명확성을 위해 B를 발생하는 경우 그 사실이되지 않습니다 시도 밖에서 선언 할 때 은 여전히 ​​범위에 있고 a.message()은 로컬 변수 이라고 부릅니다. 시도 내부에 선언 된 경우 은 더 이상 범위에 포함되지 않으므로 참조로 catch하는 의 메시지를 호출합니다. catch의 변수 이름을 변경하면 모호한 동작을 제거해야합니다.

struct base { 
    virtual void 
    rethrow() const 
    { throw *this; } 

    // it's also usual to make the base type abstract 
    // so that users can't slice, e.g. boost::exception 
    // it's also possible to make copying protected 
}; 

struct derived: base { 
    void 
    rethrow() const override 
    { throw *this; } 
}; 

void 
foo(base const& b) 
{ 
    // no: slices 
    // throw b; 

    b.rethrow(); // Ok 
} 
+1

: 난 그냥 (또한 복제라고도 함) 가상 사본처럼이 기지를 통해 복사를 해결할 수 있음을 지적 할 필요를 느끼지 완전성을 위해서 –

+0

나는 무엇이 어떤 조건 하에서 던져 지는지 정확히 알 수 없었다. 방금 try 또는 try 내부에서 a가 선언되면 다른 동작이 있다는 것을 마지막 문장에서 확인했습니다. 이처럼 변수 이름 "a"를 재사용 할 이유가 ** 없기 때문에 이것을 정리하는 것이 현명한 것 같습니다. 왜 누군가가 그것이 나쁜 생각이라고 생각하는지 확신하지 못합니다. – Tod

+1

downvote는 당신의 충고가 나쁘기 때문에가 아닙니다. 좋은 조언입니다. 문제의 답이 아니기 때문입니다. –

2

는 가상 (재) 던져베이스를 통해 던지는 해결한다 `a`가 사용 된 경우, 관찰 된 메시지를 표시해서는 안됩니다.