문제

단일 객체를 할당하면이 코드는 제대로 작동합니다. 배열 구문을 추가하려고하면 SEGFAULTS가 있습니다. 왜 이런거야? 여기서 내 목표는 외부 세계에서 클래스 C가 내부적으로 B 객체를 사용하고 있다는 사실을 외부 세계에서 숨기는 것입니다. 프로그램을 게시했습니다 코드 패드 당신이 함께 놀 수 있습니다.

#include <iostream>

using namespace std;

// file 1

class a
{
    public:
        virtual void m() { }
        virtual ~a() { }
};

// file 2

class b : public a
{
    int x;

    public:
        void m() { cout << "b!\n"; }
};

// file 3

class c : public a
{
    a *s;

    public:
        // PROBLEMATIC SECTION
        c() { s = new b[10]; } // s = new b;
        void m() { for(int i = 0; i < 10; i++) s[i].m(); } // s->m();
        ~c() { delete[] s; } // delete s;
        // END PROBLEMATIC SECTION
};

// file 4

int main(void)
{
    c o;

    o.m();

    return 0;
}
도움이 되었습니까?

해결책

한 가지 문제는 표현입니다 s[i] 포인터 산술을 사용하여 원하는 객체의 주소를 계산합니다. 부터 s 포인터로 정의됩니다 a, 결과는 배열에 맞습니다 aS와 배열의 경우 부정확합니다 b에스. 상속이 제공하는 동적 바인딩은 메소드, 다른 방법으로 만 작동합니다 (예 : 가상 데이터 구성원 없음, 가상 없음 sizeof). 따라서 방법을 호출 할 때 s[i].m() 그만큼 this 포인터는 무엇이 될 것인지 설정됩니다 ith a 배열에서 개체. 그러나 실제로 배열은 하나입니다 bs, 그것은 객체의 중간 어딘가에 가리키며 (때로는) segfault를 얻습니다 (아마도 프로그램이 객체의 vtable에 액세스하려고 할 때). 가상화 및 과부하로 문제를 해결할 수 있습니다. operator[](). (그래도 그것이 실제로 작동하는지 보려고 생각하지 않았습니다.)

또 다른 문제는입니다 delete 비슷한 이유로 소멸자에서. 당신은 그것을 가상화하고 과부하 할 수 있습니다. (다시, 내 머리에 튀어 나온 무작위 아이디어. 작동하지 않을 수도 있습니다.)

물론 캐스팅 (다른 사람들이 제안한대로)도 효과가 있습니다.

다른 팁

10의 배열 생성 b함께 new 그런 다음 주소를 an에 할당합니다 a* 단지 문제를 요구하고 있습니다.

배열을 다형성으로 처리하지 마십시오.

자세한 내용은 참조하십시오 ARR39-CPP. 배열을 다형성으로 처리하지 마십시오, 섹션에서 06. 배열 및 STL (ARR)CERT C ++ 보안 코딩 표준.

"A"유형이 아닌 유형의 "B"배열이 있으며 A 형의 포인터에 할당합니다. 다형성은 동적 어레이로 전달되지 않습니다.

 a* s

a

 b* s

그리고 당신은이 시작이 작동하는 것을 볼 것입니다.

아직 바지가 아닙니다 포인터 다형성으로 처리 될 수 있습니다. 그것에 대해 생각하십시오

 a* s = new B(); // works
 //a* is a holder for an address

 a* s = new B[10]
 //a* is a holder for an address
 //at that address are a contiguos block of 10 B objects like so
 // [B0][B2]...[B10] (memory layout)

S를 사용하여 배열을 반복 할 때 사용 된 내용에 대해 생각해보십시오.

 s[i]
 //s[i] uses the ith B object from memory. Its of type B. It has no polymorphism. 
 // Thats why you use the . notation to call m() not the -> notation

방금 배열로 변환하기 전에

 a* s = new B();
 s->m();

s는 주소 일뿐입니다. s [i]와 같은 정적 객체가 아닙니다. 주소 S만이 동적으로 결합 될 수 있습니다. s 란 무엇입니까? 누가 알아? 주소에서 뭔가.

보다 아리C 스타일 배열이 어떻게 배치되는지에 대한 자세한 내용에 대한 자세한 내용은 아래의 훌륭한 답변입니다.

B의 각 인스턴스에는 X 데이터 부재와 "VPTR"(가상 테이블에 대한 포인터)가 모두 포함됩니다.

A의 각 인스턴스에는 "VPTR"만 포함합니다.

따라서 (a)! = 크기의 크기 (b).

이제이 작업을 수행하면 "S = New B [10]RAW (A*의 유형이있는)의 M 메모리 10 인스턴스에 놓여 있습니다.

C :: m () 메소드에서 컴파일러에게 "A"배열을 반복하도록 지시합니다 (s 유형이 있기 때문에), 하지만 , S는 실제로 "B"배열을 가리키고 있습니다. 따라서 컴파일러가 실제로하는 일을 S [i]라고 부를 때 "s + i * sizeof (a)"인데, 컴파일러는 "b"의 단위 대신 "a"단위로 점프하고 a와 b가 없기 때문에 같은 크기는 많은 맘 보주 보를 얻습니다.

나는 당신의 답변을 바탕으로 해결 방법을 알아 냈습니다. 간접 계층을 사용하여 구현 세부 사항을 숨길 수 있습니다. 또한 배열에서 객체를 믹싱하고 일치시킬 수 있습니다. 감사!

#include <iostream>

using namespace std;

// file 1

class a
{
    public:
        virtual void m() { }
        virtual ~a() { }
};

// file 2

class b : public a
{
    int x;

    public:
        void m() { cout << "b!\n"; }
};

// file 3

class c : public a
{
    a **s;

    public:
        // PROBLEMATIC SECTION
        c() { s = new a* [10]; for(int i = 0; i < 10; i++) s[i] = new b(); }
        void m() { for(int i = 0; i < 10; i++) s[i]->m(); }
        ~c() { for(int i = 0; i < 10; i++) delete s[i]; delete[] s; }
        // END PROBLEMATIC SECTION
};

// file 4

int main(void)
{
    c o;

    o.m();

    return 0;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top