추상 클래스 질문좀하겠습니다.

프로그래밍 일반에 관한 포럼입니다.

Moderator: 류광

Locked
비회원

추상 클래스 질문좀하겠습니다.

Post by 비회원 »

안녕하세요 질문좀 드릴게요 ^^

제가 클래스 추상화,다형성 연습중인데요 아래 코드가 에러가 나서요 ㅠㅠ

class Animal
{
public:
Animal(){};
virtual ~Animal(){};
virtual void Move() = 0;
public:
int nAge;
};


class Dog : public Animal
{
public:
Dog(){};
~Dog(){};
virtual void Move()
{
cout << "Dog! Move" << endl;
}
private:
int nDog;
};


class Cat : public Animal
{
public:
Cat(){};
~Cat(){};
virtual void Move()
{
cout << "Cat! Move" << endl;
}
private:
int nCat;
};

int main()
{
Animal* a = new Cat[10];

for(int i = 0 ; i < 10 ; i++)
a.Move();

delete []a;

return 0;
}

위 코드에서 왜 에러가 나는지 몰르겠습니다.

cat 이나 dog 자식클래스에 멤버 변수가 없을시는 잘되는데 멤버 변수가 있으면 에러가나네요
skotos
Posts: 11
Joined: 2006-09-04 15:33

생성이 문제인듯합니다.

Post by skotos »

배열크기 생성자와 받는쪽 클래스의 크기 차이에 의해서 생긴 버그입니다.

Animal* a = new Animal[10];

for( int i = 0 ;i < 10 ; i++)
a = new Cat;


이것으로 바꾸시면 해결될듯합니다.
비회원

Re: 생성이 문제인듯합니다.

Post by 비회원 »

skotos wrote:배열크기 생성자와 받는쪽 클래스의 크기 차이에 의해서 생긴 버그입니다.

Animal* a = new Animal[10];

for( int i = 0 ;i < 10 ; i++)
a = new Cat;


이것으로 바꾸시면 해결될듯합니다.


우선 답변 감사드립니다.. 말씀해주신데로 할려고 하는데

Animal 클래스가 추상클래스여서 인스턴스화 되질 않습니다.~ ㅜㅜ
dwloiter
Posts: 30
Joined: 2005-08-09 06:05
Location: Gamblic

Post by dwloiter »

Animal** a = new Animal*[10];
for (int i = 0; i < 10; ++i)
{
a = new Cat();
}

for(int i = 0 ; i <10; ++i)
Move();

for (int i = 0; i < 10; ++i)
{
delete a;
}
delete[] a;

혹시 이런 방식을 원하신건가요?
영어/ 수학 -_-;;
비회원

Post by 비회원 »

dwloiter wrote:Animal** a = new Animal*[10];
for (int i = 0; i < 10; ++i)
{
a = new Cat();
}

for(int i = 0 ; i <10; ++i)
Move();

for (int i = 0; i < 10; ++i)
{
delete a;
}
delete[] a;

혹시 이런 방식을 원하신건가요?


ㅜㅜ 너무 복잡해보이네욤

제가 하려는것은 고양이 종류가 2종류가 있습니다. 2종류는 각자 고유하게 특수한 행동을 합니다.

그래서 추상클래스로 공통점을 묵어 놓은 Animal 클래스를 만들었습니다.

그리구 Animal 클래스를 상속받아서 서로 다른 행동과 특이한점을 따로 만들고

animal* pCat[2];

pCat[0] = new Cat[10]
pCat[1] = new Cat2[10];

pCat으로 고양이들을 관리하고 싶은데요 자식클래스에서 특이한점을 체크하기 위해 멤버변수를 만들면

생성시 에러가 납니다 ㅠㅠ Animal 클래스와 자식클래스인 Cat,Cat2가 크기가 틀려서 그런건가요?

위와 같은 방법으로 밖에는 안되는건가요?
stpapa
Posts: 43
Joined: 2007-11-05 10:48

Re: 추상 클래스 질문좀하겠습니다.

Post by stpapa »

안녕하세요 ST파파입니다.

흐음... 이건 추상클래스 개념으로 접근하는게 아니고 배열 개념으로 접근해야 할 것 같습니다.
비회원 wrote: Animal* a = new Cat[10];
for(int i = 0 ; i < 10 ; i++)
a.Move();
}


배열에서의 [] 연산은 담고 있는 클래스의 크기 만큼의 이동입니다.

Code: Select all

	Animal* a = new Cat[10];
Cat으로 New를 했지만 변수는 Animal로 받았으므로 a를 하게 되면 Animal의 크기만큼 주소가 연산되어 나옵니다. 즉, a는 a의 주소+sizeof(Animal)*i 가 튀어 나오는 거죠

당연히 자식클래스에 멤버 변수가 없으면 Animal의 크기와 Cat 클래스의 크기가 동일하니 문제가 발생하지 않지만 자식클래스에 추가로 멤버 변수가 들어가면 서로 크기가 달라지므로 실행시 에러가 발생하는 것입니다.

바로 위의 답글처럼
Animal의 2차원 포인트로 잡아서 두번의 메모리 확보를 통한 Cat의 생성을 하고 시행했다면 배열엔 클래스의 주소가 들어가게 되므로 크기의 차이가 생기지 않기 때문에(둘다 주소크기가 4Byte가 되므로(32Bit시스템에서)) 문제가 발생하지 않을 것입니다.
stpapa
Posts: 43
Joined: 2007-11-05 10:48

다른 방법들

Post by stpapa »

ST파파입니다
비회원 wrote: 위와 같은 방법으로 밖에는 안되는건가요?
일단 배열에 객체를 넣지 말고 포인터를 넣는다고 생각을 바꿔보세요

포인터를 넣기만 하면 원하는 데로 Animal이라는 상위 클래스로 원하는 각각의 행위를 할 수 있게 됩니다.

방법이야 STL 벡터를 이용하거나 템플릿을 이용하거나 많이 있지만 배열과 포인터에 대한 개념을 확실히 정립하기 전까지는 이것저것 다 복잡해 보일것 같네요

Code: Select all

animal* pCat1[10];
animal* pCat2[10];

for( int i=0; i<10; i++ )
{
  pCat1[i] = new Cat;
  pCat2[i] = new Cat2;
}

차라리 이렇게 시작해서 차근히 바꿔보심이 좋을 것 같습니다
비회원

Re: 다른 방법들

Post by 비회원 »

stpapa wrote:ST파파입니다
비회원 wrote: 위와 같은 방법으로 밖에는 안되는건가요?
일단 배열에 객체를 넣지 말고 포인터를 넣는다고 생각을 바꿔보세요

포인터를 넣기만 하면 원하는 데로 Animal이라는 상위 클래스로 원하는 각각의 행위를 할 수 있게 됩니다.

방법이야 STL 벡터를 이용하거나 템플릿을 이용하거나 많이 있지만 배열과 포인터에 대한 개념을 확실히 정립하기 전까지는 이것저것 다 복잡해 보일것 같네요

Code: Select all

animal* pCat1[10];
animal* pCat2[10];

for( int i=0; i<10; i++ )
{
  pCat1[i] = new Cat;
  pCat2[i] = new Cat2;
}

차라리 이렇게 시작해서 차근히 바꿔보심이 좋을 것 같습니다
답변 해주신분들 모두 감사합니다. 배열에 대해서 다시한번 생각해봤습니다 ㅠㅠ
비회원

설계오류가 코드오류가 되는 상황이네요.

Post by 비회원 »

int main()
{
Animal* a = new Cat[10];

for(int i = 0 ; i < 10 ; i++)
a.Move();

delete []a;

return 0;
}


이 예에서, Animal* a은 객체 인스턴스를 담기위한 배열이 아니라 Animal 객체의 포인터를 담기위한

배열이 되어야 하는데, 선언자체를 보자면 new Cat[10]를 할당했으므로 실제 Animal의 인스턴스가

들어간 배열이 되었습니다. C++ 언어가 이걸 허용한다는 자체가 난센스일지도 모르겟네요.

즉, 예제는 Animal* a에 Animal객체의 인스턴스가 아닌 포인터를 담도록 이렇게 수정되어야 합니다.


보통, 다형클래스의 저장소는 선언과 동시에 인스턴스가 할당되는 경우가 없기 때문에 피부에 잘 피부에

와닫지 않지만 명백한 설계상의 오류라고 지적한 것입니다, 선언시 저장소안의 모든 포인터의 타입이

결정된다면 다형성 자체가 필요없죵.


void main()
{
// 포인터10개 생성
Animal** a = new Animal*[10];

// 포인터에 인스턴스 생성
for(int i = 0; i < 10; i++)
{
a = new Cat;
}

// 사용
for(int i = 0; i < 10; i++)
{
a->Move();
}

// 인스턴스 해제
for(int i = 0; i < 10; i++)
{
delete a;
}

// 포인터10개 제거
delete[] a;
}
비회원

객체 a의 잘못된 메모리 접근입니다.

Post by 비회원 »

메인함수
===========================
Animal* a = new Cat[10]; // (1)번

for(int i = 0 ; i < 10 ; i++)
a.Move(); // (2)번

delete []a;

return 0;
===========================

(1)번 부분에서 메모리 할당시 부모인 Animal부분과 상속된 자식인 Cat부분 메모리가
한 셋트로 해서 10개 할당이 됩니다.

-----------------------------------------------------------------------
[ Animal | Cat ][ Animal | Cat ][ Animal | Cat ] ......
-----------------------------------------------------------------------

하지만 할당 받은 포인터 a는 Animal 포인터 타입이기 때문에 문법적으로는 Cat이 제외된 Animal부분만 따라가게되죠.

(2)번 부분에서 단순히 a라고 명시를 한다면 a가 Animal 포인터 타입이므로

원하는 접근은..
-----------------------------------------------------------------------
[ Animal | Cat ][ Animal | Cat ][ Animal | Cat ] ...... (3)번
-----------------------------------------------------------------------
이렇겠지만 정작 실제로는
-----------------------------------------------------------------------
[ Animal ][ Animal ][ Animal ][ Animal ].....
-----------------------------------------------------------------------
이렇게 접근 해버리기 때문에 메모리상에서 오류가 뜨게 됩니다.

이것을 해결하기 위해서는

(2)번의 a부분의 타입을 Animal 포인터 타입이 아닌 Cat의 포인터 타입으로 바꿔주기 위해.
Type Cast 시켜주면 됩니다.

a.Move() => ((Cat *)a).Move()

이와 같이 바꿔주면 메모리를 (3)번과 같이 접근하기 때문에 오류가 해결될 것입니다.

도움이 되셨는지 모르겠네요.
비회원

창문이 하나 깨지면 계속 깨짐.

Post by 비회원 »

윗분말씀대로 dynamic_cast<Cat*>를 이용하면 배열인덱싱에서 오류를 피할 수는 있겠지요.

허나

delete[] a;

에서 또 오류가 발생합니다. 그럼 결국...

delete[] dynamic_cast<Cat*>(a);

하셔야할거고...

이런식으로 소스가 온천지 캐스팅으로 도배되겠군요.ㅋ
Locked