2016-07-03 1 views
3

그것은 나에게 포인터 공분산을 가지고 ++이 C를 발생하지 따라서이 같은 다리에 자신을 촬영할 수 있습니다 : 그것은 정의되지 않은 행동C++ 포인터 공분산

struct Base 
{ 
    Base() : a(5) {} 
    int a;  
}; 

struct Child1 : public Base 
{ 
    Child1() : b(7) {} 
    int b; 
    int bar() { return b;} 
}; 

struct Child2 : public Base 
{ 
    Child2(): c(8) {} 
    int c; 
}; 

int main() 
{ 
    Child1 children1[2]; 

    Base * b = children1; 

    Child2 child2; 

    b[1] = child2; // <------- now the first element of Child1 array was assigned a value of type Child2 

    std::cout << children1[0].bar() << children1[1].bar(); // prints 57 
} 

인가? 그것을 방지하는 방법이 있습니까 아니면 적어도 컴파일러에서 경고가 있습니까?

답변

2

예, 이것은 정의되지 않은 동작입니다.

아니, 전형적인 C++ 컴파일러는 여기에서 진단을받을만한 것을 식별 할 수 없을 것입니다. 그러나 C++ 컴파일러는 지나가는 해가 갈수록 더 똑똑해집니다. 첫 번째 요소 아니다

b[1] = child2; // <------- now the first element of Child1 array was assigned... 

번호 : 누가 ... 지금부터 업무, 년의 상태 일 무슨 그러나

, 작은 애매한 알고있다. 그것은 두 번째 요소입니다. b[0]이 첫 번째 요소입니다. 또한 b은 배열이 아니므로 포인터입니다. 그리고 그것은 하나의 요소에 대한 포인터입니다. 두 요소 배열에 대한 포인터가 아닙니다.

그리고 이것이 정의되지 않은 동작의 출처입니다.

Base * b = children1; 

children1Child1 *에 붕괴 : 때문에

는 배열이 아니다 이유입니다. 그것이 사건이 끝난 곳이라면, b은 2 요소 배열에 대한 포인터가 될 것이라고 말할 수 있습니다.

하지만 상황이 끝난 곳이 아닙니다. 쇠퇴 한 포인터는 Base *으로 캐스팅되었습니다. 하위 클래스에 대한 포인터를 수퍼 클래스에 대한 포인터로 암시 적으로 캐스트 할 수 있습니다. 하지만 (느슨하게 말하자면) 슈퍼 클래스 배열에 대한 하위 클래스 배열에 대한 포인터를 캐스트 할 수 없습니다. 따라서 b은 엄격하게 단일 요소에 대한 포인터이며 b[1]은 정의되지 않은 동작이됩니다.

+0

제로 요소를 b [0] (으)로 호출하는 데 익숙합니다. 그리고 실제로 배열을 만드는 것은 꼭 필요한 것은 아닙니다. 하나의 Child1 child1을 생성 할 수 있습니다. 기본 * b = & child1; * b = child2; 그리고 정의되지 않은 동일한 동작을 얻지 못합니까? – Amomum

+0

아니요, 이것은 완벽하게 정의 된 동작입니다. –

+0

@Amomum : 물론 정의가 잘되어 있다고해서 좋은 생각이 들지는 않습니다. 당신이 생각하는대로 행동한다는 의미도 아닙니다. –