- 객체 포인터
Circle 객체에 대한 포인터 변수를 선언하고 활용하는 사례를 보자.
1 2 3 4 5 6 | Circle donut; double d = donut.getArea(); Circle *p; p = &donut; d = p->getArea(); | cs |
먼저 Circle타입의 객체에 대한 포인터 변수는 다음과 같이 선언한다.
1 | Circle *p; | cs |
포인터 변수 p에 객체 donut의 주소를 저장한다.
1 | p = &donut; | cs |
이때, 선언과 동시에 초기화를 할 수 도 있다.
초기화가 되어있지 않다면 멤버로 접근할 수 없다.
1 | Circle *p = &donut; | cs |
객체 이름으로 접근할때는 점(.)을 이용하지만
1 | d = donut.getArea(); | cs |
객체 포인터로 접근할 때는 -> 연산자를 이용한다.
1 2 | d = p->getArea(); //d = (*p).getArea(); 와 | cs |
- 객체 배열
객체 배열은 원소가 객체라는점을 빼고, int, double등 기본타입의 배열을 선언하고 활용하는 방법과 동일하다.
다음 코드는 Circle 객체의 배열 circleArray를 선언하는 코드이다.
1 | Circle circleArray[3]; | cs |
객체 배열 선언문은 기본 생성자를 호출한다.
아무런 생성자도 선언되어있지 않으면 기본 생성자를 호출한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <iostream> using namespace std; class Circle{ int radius; public: double getArea(){ return 3.14*radius*radius; } }; int main(){ Circle circleArray[3]; //기본 생성자 호출 } | cs |
다음과 같이 기본생성자가 아닌 매개변수를 가진 생성자만 선언되어 있는 경우는
객체 배열로 선언을 하면 기본생성자가 없기때문에 컴파일에러가 발생한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <iostream> using namespace std; class Circle{ int radius; public: Circle(int r) { radius = r; } //매개변수가 있는 double getArea(){ return 3.14*radius*radius; } }; int main(){ Circle circleArray[3]; //컴파일에러 } | cs |
Circle 객체의 setRadius() 멤버함수를 호출하는 코드인데, 원소와 객체 사이에 점(.) 연산자를 사용한다.
1 2 3 | circleArray[0].setRadius(10); circleArray[1].setRadius(20); circleArray[2].setRadius(30); |
또는 다음과 같은 방법으로 초기화도 가능하다.
1 | Circle circleArray[3] = { Circle(10), Circle(20), Circle() }; | cs |
소멸자도 마찬가지로
각 원소의 객체마다 소멸자가 호출되며, 높은 인덱스의 원소 객체가 먼저 소멸된다.
circleArray[2] 소멸자 실행 -> circleArray[1] 소멸자 실행 -> circleArray[0]
다차원 객체배열의 경우도 동일하다.
2행 3열의 2차원 객체배열을 생성하기 위해서는 아래의 코드를 작성하면 된다.
1 | Circle circles[2][3]; | cs |
초기화까지 한번에 하고싶다면, 다음과 같이 하면 된다.
아무런 매개변수를 전달하지 않은 생성자는 당연히 기본 생성자가 생성되어 기본으로 설정해 두었던 1로 세팅이 된다.
1 2 | Circle circles[2][3] = { {Circle(1), Circle(2), Circle(3)}, {Circle(4), Circle(5), Circle()} }; | cs |
- 동적 메모리 할당 및 반환
C언어 : malloc(), free() 등의 표준 함수 사용
C++ : new, delete 연산자를 사용
new 연산자는 힙(heap) 에서 메모리를 할당받고, delete 연산자는 다시 메모리를 힙(heap)으로 반환한다.
new와 delete 연산자의 기본 형식은 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 | /* 데이터타입 *포인터변수 = new 데이터타입; delete 포인터변수; */ int *pInt = new int; // int 타입의 정수 공간 할당 char *pChar = new char; // char 타입의 문자 공간 할당 Circle *pCircle = new Circle //Circle 클래스 타입의 객체 할당 delete pInt; delete pChar; delete pCircle; | cs |
이때, 힙(heap) 메모리가 부족하다면 new는 NULL을 return 하므로, new의 return 값이 NULL인지 아닌지 검사하는것이 좋다.
1 2 3 4 5 6 7 | int *p = new int; // int 타입의 정수 공간 p 할당 if(!p){ // p==NULL 과 동일 return; } *p = 5; int n = *p; delete p; //포인터 p는 살아있지만, 할당된 영역이 없으므로 접근하면 안된다. | cs |
동적 메모리 할당과 동시에 초기화도 가능한데 다음과 같이 하면된다.
1 2 3 4 5 | /* 데이터타입 *포인터변수 = new 데이터타입(초깃값); */ int *pInt = new int(20); char *pChar = new char('a'); | cs |
delete사용시 주의할 점이 있는데,
첫번째로 동적으로 할당받지 않은 메모리를 반환할 때 이다.
1 2 3 | int n; int *p = &n; delete p; //실행 오류. p가 가리키는 n은 정적으로 할당받은 메모리이다. | cs |
두번째로 이미 반환한 메모리를 한번 더 반환할 때 이다.
중복으로 메모리를 반환할 수는 없다.
1 2 3 | int *p = new int; delete p; //정상 반환 delete p; //실행 오류. 이미 반환됨. | cs |
배열도 동적할당을 할 수 있는데, 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 | /* 데이터타입 *포인터변수 = new 데이터타입 [배열의크기]; delete [] 포인터변수; */ int *p = new int[5]; if(!p) return; for(int i=0; i<5; ++i) p[i] = i; //동적으로 할당 받은 배열은 []를 이용하여 보통 배열과 동일한 방법으로 사용한다. delete [] p; | cs |
하지만 new로 배열을 동적 할당받을때 생성자를 통해 초기화는 불가능하다.
그래서 다음과 같이 초기화를 한다.
1 | int *pArray = new int[] {1,2,3,4}; | cs |
'CS > C++' 카테고리의 다른 글
7. C++ 함수의 인자 전달 방식, 함수 호출시 객체 전달, 객체 치환 및 객체 리턴 (0) | 2019.02.11 |
---|---|
6. C++ 객체와 객체 배열의 동적 생성 및 반환, this포인터, string 클래스를 이용한 문자열 사용 (0) | 2019.02.11 |
4. C++ 접근지정, C++ 인라인 함수, C++ 구조체, C++바람직한 코딩 (0) | 2018.11.19 |
3. C++ 클래스(Class), 생성자(Constructor), 소멸자(Destructor) (0) | 2018.11.14 |
2. C++ 객체란? (0) | 2018.11.14 |