객체 포인터
객체에 대한 포인터 변수 선언
Circle *p;
현재 선언된 포인터 변수 p는 아무 객체도 가리키지 않는다
포인터 변수에 객체 주소 지정
p = &donut;
포인터 변수 선언 시 객체 주소로 초기화
Circle* p = &donut;
포인터를 이용한 객체 멤버 접근
객체 이름으로 멤버에 접근할 때는 다음과 같이 점(.) 연산자를 이용하지만,
d = donut.getArea(); //객체 이름으로 멤버 함수 호출
객체 포인터로 멤버 접근할 때는 -> 연산자를 사용한다.
다음 코드는 p가 가리키는 객체의 getArea()함수를 호출한다.
d = p->getArea(); //포인터로 객체 멤버 함수 호출
d = (*p).getArea(); //위 코드와 같은 의미
CheckTime
Polygon poly;
Polygon *p;
1)포인터 p를 활용해 poly객체의 draw()함수를 호출하는 코드를 두 줄로 작성해라
p= &poly;
cout << p->draw() << endl;
cout << (*p).draw() <<endl;
2) 4번
객체 배열
객체 배열 선언
Circle circleArray[3];
위와 같이 선언한다
객체 배열 선언문은 기본 생성자를 호출
객체 배열 선언문은 오직 매개 변수가 없는 기본 생성자를 호출한다
Circle circleArray[3];
3개의 객체 생성 후, 각 객체마다 다음의 기본 생성자가 호출
Circle::Circle(){radius=1;}
컴파일러가 자동으로 기본 생성자를 삽입하므로, 객체 배열 생성 시 컴파일 오류가 발생하지 않는다.
매개변수가 있는 생성자가 있는데, 기본 생성자를 선언하지 않는다면 컴파일 에러가 발생한다.
객체 배열 사용
배열의 각 원소 객체는 [ ]연산자로 구분한다
원소 객체와 멤버 사이에 점(.) 연산자를 사용하여 멤버 함수를 호출한다.
for(int i=;i<3;i++)
cout << "Circle" << i << "의 면적은 "<< circleArray[i].getArea() << endl;
동일한 기능을 해도 포인터를 통해 위의 코드를 아래와 같이 바꿀 수 있다.
Circle *p;
p- circleArray;
for(int i=0;i<3;i++){
cout << "Circle " << i << "의 면적은 " << p->getArea() <<endl;
p++;
}
배열 소멸과 소멸자
함수가 종료하면 함수 내에 선언된 배열도 소멸된다.
배열이 소멸되면, 모든 원소 객체가 소멸되며 각 원소 객체마다 소멸자가 호출된다.
main()함수가 종료하면 circleArray배열이 소멸되며, 높은 인덱스에서부터 원소 객체가 소멸되고, 각 객체마다 ~Circle()소멸자가 실행된다.
circleArray[2] 소멸자 진행 -> circleArray[1] 소멸자 진행 -> circleArray[0] 소멸자 진행
객체 포인터를 통해 객체 배열을 다루는 다양한 방법
객체 포인터를 이용해 circleArray의 각 Circle객체의 면적을 추력하는 코드를 다양하게 작성 가능
1)포인터 p를 이용해 객체처럼 접근
Circle *p = circleArray;
for(int i=0; i<3; i++)
cout << (*p++).getArea() << endl;
2) 배열의 이름 circleArray를 포인터로 사용
for(int i=0; i<3; i++)
cout << (circleArray+i)->getArea() << endl;
3) 포인터 p의 정수 연산 이용
Circle *p = circleArray;
for(int i=0; i<3; i++)
cout << (p+i) -> getArea();
객체 배열 초기화
객체 배열 생성 시 생성자를 사용해 다음과 같이 원소 객체 초기화가 가능하다.
Circle circleArray[3] = { Circle(10), Circle(20), Circle() };
다차원 객체 배열
Circle circles[2][3];
2차원 배열도 일차원 배열과 동일하게, 각 원소 객체가 생성될 때 기본 생성자 Circle()이 실행되어 모든 객체의 radius 값이 1이 된다. 각 객체의 radius 값을 1에서 6까지로 초기화하고 싶다면 다음과 같이 진행
circles[0][0].setRadius(1);
circles[0][1].setRadius(2);
circles[0][2].setRadius(3);
circles[1][0].setRadius(4);
circles[1][1].setRadius(5);
circles[1][2].setRadius(6);
다음과 같이 { } 안에 생성자를 지정해 배열을 초기화할 수 있다.
배열의 초기화된 결과는 이와 같다
Circle circles[2][3] = { { Circle(1), Circle(2), Circle(3) },
{ Circle(4), Circle(5), Circle(6) } };
CHECKTIME
class Sample{
int a;
public:
Sample(){ a = 100; cout << a << ' ';}
Sample(int x) { a = x; cout << a << ' ';}
Sample(int x, int y){ a = x*y; cout << a << ' ';}
int get() { return a;}
};
1) Sample arr[3]; 이 실행될 때 출력되는 결과는?
3
2) Sample arr2D [2] [2] = { {Sample(2, 3), Sample(2, 4) }, {Sample(5), Sample()} };이 실행될 때 출력되는 결과는?
6 8 5 100
3) 객체 포인터를 이용해 (1)에서 선언된 arr의 모든 원소(a)의 합을 출력하는 for문을 작성하라.
for(int i=0; i<2; i++){
int SumA +=arr[i];
}
4) (2)에서 선언된 arr2D 배열 이름을 이용해 모든 원소(a)의 합을 출력하는 for문을 작성하라
for(int i=0; i<2; i++){
for(int j=0; j<2; j++){
int cnt +=arr2D[i][j].get();
}
}
동적 메모리 할당 및 반환
동적 메모리 할당
: 보통 개발자는 프로그램 작성 단계에서 필요한 메모리 확보를 위해 변수, 객체, 배열을 정적으로 선언한다.
실행 중에 필요한 만큼 메모리를 할당받고 필요 없을 때 반환하는 '동적 메모리 할당/ 반환 메커니즘'이 필요하다.
이처럼 C에서는 동적 메모리 할당 및 반환을 위해 malloc()/ free()등에 표준 C를 사용하지만, C++에서는 new와 delete연산자를 이용한다. new 연산자는 힙(heap)이라는 공간으로부터 메모리를 할당받고, delete 연산자는 할당받은 메모리를 힙으로 반환한다.
new와 delete 연산자
= new와 delete의 기본 형식
데이터타입 *포인터변수 = new 데이터타입;
delete 포인터변수;
new 연산자
: '데이터타입'의 크기만큼 힙으로부터 메모리를 할당받고 주소를 리턴
'포인터변수'는 할당받은 메모리의 주소를 가진다
delete 연산자
: '포인터변수'가 가리키는 메모리를 힙으로 반환
'데이터타입'은 int, char, double 등 기본 타입뿐 아니라 구조체(struct), 클래스(class)도 포함한다
int *pInt = new int; //int타입에 정수공간할당
char *pChar = new char; //char 타입의 문자 공간 할당
Circle *pCircle = new Circle(); //cIRCLE 클래스 타입의 객체 할당
delete pInt; //할당받은 정수 공간 반환
delete pChar; //할당받은 문자 공간 반환
delete pCircle; //할당받은 객체 공간 반환
힙 메모리가 부족하면 new는 NULL을 리턴하므로, new의 리턴 값이 NULL인지 검사하는 것이 좋다.
int *p = new int; //힙으로부터 int 타입의 정수 공간 할당
if(!p) { // if(p==NULL)과 동일. p가 NULL이면
return; //메모리 할당받기 실패
}
*p = 5; //할당받은 정수공간에 5 기록
int n = *p; //할당받은 정수 공간에서 값 읽기, n=5;
delete p; //할당받은 정수 공간 반환
동적 할당 메모리 초기화
데이터타입 *포인터변수 = new 데이터타입(초깃값);
delete 사용 시 주의
동적 할당받지 않는 메모리를 반환해 실행 오류가 발생
int n;
int *p = &n;
delete p; //실행 오류. p가 가리키는 메모리는 동적 할당받은 것이 아님
마찬가지로 동일 메모리를 두 번 반환시 실행 오류가 발생
int *p = new int;
delete p; //정상적인 메모리 반환
delete p; //이미 메모리 반환을 했기에 실행 오류 발생
배열을 초기화할 때 주의 사항
new로 배열을 동적 할당받을 때 다음과 같이 생성자를 통해 직접 '초깃값'을 지정할 수 없다.
int *pArray = new int[10](20); //구문 오류. 배열의 초기화는 불가
int *pArray = new int(20)[10]; //구문 오류
다음과 같이 초깃값을 지정 가능
int *pArray = new int [ ] {1,2,3,4} // 1, 2, 3, 4로 초기화된 정수 배열 생성
배열을 delete할 때 주의 사항
배열을 반환할 때 delete연산자의 사용에 주의
--------------------------------------------------------------------------------------------------
int *p = new int [10];
delete p; //비정상 반환, delete [ ] p; 로 해야함
int *q = new int;
delete [ ] q; //비정상 반환. delete q; 로 해야함
--------------------------------------------------------------------------------------------------
'Language & Framework & GIT > C++' 카테고리의 다른 글
[씨앤씨뿔]C++의 getline함수 (4) | 2023.04.27 |
---|---|
[씨앤씨뿔]C++ / 객체 포인터 &배열 &동적 생성 - 2 (0) | 2023.04.26 |
[씨앤씨뿔]C++/ 클래스 & 객체 - 2 (1) | 2023.04.19 |
[씨앤씨뿔]C++/ 클래스 & 객체 - 1 (0) | 2023.04.18 |
[씨앤씨뿔]C++/ C++의 기본 - 3 (0) | 2023.04.17 |
댓글