기준점에 대한 포인터가 파생 개체의 배열을 가리킬 수 있습니까?


99

저는 오늘 면접을 보러 갔고이 흥미로운 질문을 받았습니다.

메모리 누수와 가상 dtor가 없다는 사실 외에도이 코드가 충돌하는 이유는 무엇입니까?

#include <iostream>

//besides the obvious mem leak, why does this code crash?

class Shape
{
public:
    virtual void draw() const = 0;
};

class Circle : public Shape
{
public:
    virtual void draw() const { }

    int radius;
};

class Rectangle : public Shape
{
public:
    virtual void draw() const { }

    int height;
    int width;
};

int main()
{
    Shape * shapes = new Rectangle[10];
    for (int i = 0; i < 10; ++i)
        shapes[i].draw();
}

1
누락 된 세미콜론 외에는 요? (하지만 런타임이 아닌 컴파일 타임 오류)
Platinum Azure

모두 가상 이었습니까?
Yochai Timmer 2011-08-25

8
그것은 Shape **직사각형의 배열을 가리키고 있어야합니다 . 그런 다음 액세스는 shapes [i]-> draw ();
RedX

2
@Tony 행운을 빕니다, 우리에게 계속 알려주세요 :)
Seth Carnegie

2
@AndreyT : 코드는 이제 정확합니다 (원래도 정확했습니다). 은 ->편집자에 의해 실수였다.
R. Martinho Fernandes

답변:


150

그런 식으로 색인을 생성 할 수 없습니다. 의 배열을 할당하고 Rectangles의 첫 번째에 대한 포인터를 저장했습니다 shapes. 당신이 shapes[1]할 때 당신은 (shapes + 1). 이것은 다음에 대한 포인터를 제공하지 Rectangle않지만 Shape, 추정 된 배열에서 다음 에 대한 포인터를 제공합니다 Shape. 물론 이것은 정의되지 않은 동작입니다. 귀하의 경우에는 운이 좋으며 충돌을 겪고 있습니다.

포인터를 Rectangle사용하여 인덱싱이 올바르게 작동합니다.

int main()
{
   Rectangle * shapes = new Rectangle[10];
   for (int i = 0; i < 10; ++i) shapes[i].draw();
}

Shape배열에 다른 종류의 s를 포함하고 다형 적으로 사용 하려면 Shape 에 대한 포인터 배열이 필요합니다 .


37

Martinho Fernandes가 말했듯이 인덱싱이 잘못되었습니다. 대신 Shape 배열을 저장하려면 다음과 같이 Shape * 배열을 사용하여 저장해야합니다.

int main()
{
   Shape ** shapes = new Shape*[10];
   for (int i = 0; i < 10; ++i) shapes[i] = new Rectangle;
   for (int i = 0; i < 10; ++i) shapes[i]->draw();
}

배열을 초기화하면 개체 자체가 아닌 포인터 만 설정하므로 Rectangle을 초기화하는 추가 단계를 수행해야합니다.


13

포인터를 인덱싱 할 때 컴파일러는 배열 내부에있는 크기에 따라 적절한 양을 추가합니다. 따라서 sizeof (Shape) = 4 (멤버 변수가 없기 때문에)라고 말합니다. 그러나 sizeof (Rectangle) = 12 (정확한 숫자는 틀릴 가능성이 높습니다).

따라서 첫 번째 요소에 대해 0x0에서 시작하여 색인을 생성 할 때 10 번째 요소에 액세스하려고 할 때 잘못된 주소 또는 개체의 시작이 아닌 위치로 이동하려고합니다.


1
C ++에 능숙하지 않은 사람으로서 SizeOf ()를 언급하면 ​​@R이 무엇인지 이해하는 데 도움이되었습니다. Martinho는 그의 대답에서 말했습니다.
Marjan Venema
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.