Search
Duplicate

4장. 객체 포인터와 객체 배열, 객체의 동적 생성

생성일
2022/04/04 13:50
태그
C++

객체 포인터와 객체 배열, 객체의 동적 생성

객체 포인터

객체에 대한 포인터
C언어의 포인터와 동일
객체의 주소 값을 가지는 변수
포인터로 멤버를 접근할 때
객체포인터 → 멤버
Circle donut; double d = donut.getArea(); Circle *p; // 객체에 대한 포인터 선언 p = &donut; // 포인터에 객체 주소 저장 d = p->getArea(); // 멤버 함수 호출
C++
복사
main.cpp
int main() { Circle donut; Circle pizza(30); // 객체 이름으로 멤버 접근 cout << donut.getArea() << endl; // 객체 포인터로 멤버 접근 Circle *p; p = &donut; // donut의 getArea() 호출 cout << p->getArea() << endl; cout << (*p).getArea() << endl; p = &pizza; cout << p->getArea() << endl; cout << (*p).getArea() << endl; }
C++
복사

객체 배열, 생성 및 소멸

객체 배열 선언 가능
기본 타입 배열 선언과 형식이 동일
int n[3]; → 정수형 배열 선언
Circle c[3] → Circle 타입의 배열 선언
객체 배열 선언
1.
객체 배열을 위한 공간 할당
2.
배열의 각 원소 객체마다 생성자 실행
c[0] 의 생성자, c[1] 의 생성자, c[2] 의 생성자 실행
매개변수 없는 생성자 호출
매개변수 있는 생성자를 호출할 수 없음
Circle circleArray[3](5) → 오류
배열 소멸
배열의 각 객체마다 소멸자 호출
생성의 반대순으로 소멸한다
c[2]의 소멸자, c[1]의 소멸자, c[0]의 소멸자 실행
#include <iostream> #include "Circle.h" using namespace std; int main() { Circle circleArray[3]; // 배열의 각 원소 객체의 멤버 접근 circleArray[0].setRadius(10); circleArray[1].setRadius(20); circleArray[2].setRadius(30); for (int i = 0; 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++; } } }
C++
복사

객체 배열 초기화

객체 배열 초기화 방법
배열의 각 원소 객체당 생성자 지정하는 방법
Circle circleArray[3] = { Circle(10), Circle(20), Circle() };
C++
복사
int main() { //Circle 배열 초기화 Circle circleArray[3] = { Circle(10), Circle(20), Circle() }; for (int i = 0; i < 3; i++) { cout << "Circle " << i << "의 면적은 " << circleArray[i].getArea() << endl; } }
C++
복사

동적 메모리 할당 및 반환

정적 할당
변수 선언을 통해 필요한 메모리 할당
많은 양의 메모리는 배열 선언을 통해 할당
동적 할당
필요한 양이 예측되지 않는 경우, 프로그램 작성시 할당 받을 수 없다
실행 중에 힙 메모리에서 할당
힙(heap)으로부터 할당
힙은 운영체제가 프로세스의 실행을 시작 시킬 때 동적 할당 공간으로 준 메모리 공간
C 언어의 동적 메모리 할당 : malloc() / free() 라이브러리 함수 사용
C++ 의 동적 메모리 할당 / 반환
new 연산자
기본 타입 메모리 할당, 배열 할당, 객체 할당, 객체 배열 할당
객체의 동적 생성
힙 메모리로부터 객체를 위한 메모리 할당 요청
객체 할당 시 생성자 호출
delete 연산자
new로 할당 받은 메모리 반환
객체의 동적 소멸
소멸자 호출 뒤 객체르 힙에 반환

new 와 delete 연산자

C++의 기본 연산자
new / delete 연산자의 사용 형식
데이터타입 *포인터변수 = new 데이터타입; delete 포인터변수;
int *pInt = new int; // int 타입의 메모리 동적 할당 char *pChar = new char; // char 타입의 메모리 동적 할당 Circle *pCircle = new Circle(); // Circle 클래스 타입의 메모리 동적 할당 delete pInt; // 할당 받은 정수 공간 반환 delete pChar; // 할당 받은 문자 공간 반환 delete pCircle; // 할당 받은 객체 공간 반환
C++
복사
#include <iostream> using namespace std; int main() { int *p; p = new int; // int 타입 1개 할당 if (!p) { // p가 NULL 이면 메모리 할당 실패 cout << "메모리를 할당할 수 없습니다."; return 0; } *p = 5; // 할당 받은 정수 공간에 5 삽입 int n = *p; cout << "*p = " << *p << '\n'; cout << "n = " << n << '\n'; delete p; }
C++
복사

delete 사용 시 주의 사항

적절치 못한 포인터로 delete하면 실행 시간 오류 발생
동적으로 할당 받지 않는 메모리 반환 - 오류
동일한 메모리 두 번 반환 - 오류

배열의 동적 할당 및 반환

new / delete 연산자의 사용 형식
데이터타입 *포인터변수 = new 데이터타입 [배열의 크기]; //동적 배열 할당 delete [] 포인터변수; //배열반환
int *p = new int[5]; for (int i = 0; i < 5; i++) p[i] = i; delete [] p;
C++
복사
정수형 배열의 동적 할당 및 반환
#include <iostream> using namespace std; int main() { cout << "입력할 정수의 개수는?"; int n; cin >> n; if (n <= 0) return 0; int *p = new int[n]; // n 개의 정수 배열 동적 할당 if (!p) { cout << "메모리를 할당할 수가 없습니다."; return 0; } for (int i = 0; i < n; i++) { cout << i + 1 << "번째 정수 : "; cin >> p[i]; } int sum = 0; for (int i = 0; i < n; i++) sum += p[i]; cout << "평균 = " << sum / n << endl; delete [] p; // 배열 메모리 반환 }
C++
복사

동적 할당 메모리 초기화 및 delete 시 유의 사항

동적 할당 메모리 초기화
동적 할당 시 초기화
배열은 동적 할당 시 초기화 불가능
delete 시 [] 생략
컴파일 오류는 아니지만, 비정상적인 반환

객체의 동적 생성 및 반환

클래스이름 *포인터변수 = new 클래스이름; 클래스이름 *포인터변수 = new 클래스이름(생성자매개변수리스트); delete 포인터변수;
Circle *p = new Circle; Circle *q = new Circle(30); delete p; delete q;
C++
복사
#include <iostream> using namespace std; int main() { Circle *p, *q; p = new Circle; q = new Circle(30); cout << p->getArea() << endl << q->getArea() << endl; delete p; delete q; }
C++
복사
#include <iostream> using namespace std; int main() { int radius; while (true) { cout << "정수 반지름 입력(음수이면 종료)>> "; cin >> radius; if (radius < 0) break; Circle *p = new Circle(radius); // 동적 객체 생성 cout << "원의 면적은 " << p->getArea() << endl; delete p; // 객체 반환 } }
C++
복사

객체 배열의 동적 생성 및 반환

클래스이름 *포인터변수 = new 클래스이름 [배열 크기]; delete [] 포인터변수;
→ 포인터변수가 가리키는 객체 배열을 반환
Circle *pArray = new Circle[3]; pArray[0].setRadius(10); delete [] pArray;
C++
복사

객체 배열의 사용, 배열의 반환과 소멸자

동적으로 생성된 배열도 보통 배열처럼 사용
pArray[0].setRadius(10) pArray[1].setRadius(20) cout << pArray[i].getArea();
C++
복사
포인터로 배열 접근
pArray->setRadius(10); (pArray+1)->setRadius(20);
C++
복사
배열 소멸
delete [] pArray;
C++
복사
예제)
#include <iostream> #include "Circle.h" using namespace std; int main() { Circle *pArray = new Circle[3]; // 객체 배열 생성 // 각 원소 객체의 기본 생성자 Circle() 실행 pArray[0].setRadius(10); pArray[1].setRadius(20); pArray[2].setRadius(30); for (int i = 0; i < 3; i++) { cout << pArray[i].getArea() << '\n'; } Circle *p = pArray; // 포인터 p에 배열의 주소값으로 설정 for (int i = 0; i < 3; i++) { cout << p->getArea() << '\n'; p++; // 다음 원소의 주소로 증가 } delete [] pArray; // 객체 배열 소멸 // 각 배열 원소 객체의 소멸자 ~Circle() 실행 }
C++
복사

this 포인터

this

포인터, 객체 자신 포인터
클래스의 멤버 함수 내에서만 사용
개발자가 선언하는 변수가 아니고, 컴파일러가 선언한 변수
멤버 함수에 컴파일러에 의해 묵시적으로 삽입 선언되는 매개변수
class Circle { int radius; public: Circle() { this->radius = 1; } Circle(int radius) { this->radius = radius; } void setRadius(int radius) { this->radius = radius; } };
C++
복사

this 가 필요한 경우

매개변수의 이름과 멤버 변수의 이름이 같은 경우
멤버함수가 객체 자신의 주소를 리턴할 때
연산자 중복 시에 매우 필요

this 의 제약 사항

멤버 함수가 아닌 함수에서 this 사용 불가
객체와의 관련성이 없기 때문
static 멤버 함수에서 this 사용 불가
객체가 생기기 전에 static 함수 호출이 있을 수 있기 때문에

String 클래스를 이용한 문자열

C++ 문자열
C-string
C++ string 클래스의 객체
string 클래스
C++ 표준 라이브러리, <string> 헤더 파일에 선언
가변 크기의 문자열
다양한 문자열 연산을 실행하는 연산자와 멤버함수 포함
문자열 복사, 문자열 비교, 문자열 길이 등
문자열, 스트링, 문자열 객체, string 객체 등으로 혼용

string 객체 생성 및 입출력

string 객체의 동적 생성

new / delete 를 이용하여 문자열을 동적 생성 / 반환 가능
#include <string> string *p = new string("C++"); // 스트링 객체 동적 생성 cout << *p; // "C++" 출력 p->append(" Great!!"); // p가 가리키는 스티링이 C++ Great 가 된다 cout << *p; // C++ Great delete *p. // 스트링 객체 반환
C++
복사
#include <iostream> #include <string> using namespace std; int main() { string names[5]; for (int i = 0; i < 5; i++) { cout << "이름 >> "; getline(cin, names[i], '\n'); } string latter = names[0]; for (int i = 1; i < 5; i++) { if (latter < names[i]) { // 사전 순으로 latter 문자열이 앞에 온다면 latter = names[i]; // latter 문자열 변경 } } cout << "사전에서 가장 뒤에 나오는 문자열은 " << latter << endl; }
C++
복사
빈 칸을 포함하는 문자열을 입력 받고, 한 문자씩 왼쪽으로 회전하도록 문자열을 변경하고 출력하라
#include <iostream> #include <string> using namespace std; int main() { string s; cout << "문자열을 입력하세요 (한글 안됨) " << endl; getline(cin, s, '\n'); // 문자열 입력 int len = s.length(); // 문자열의 길이 for (int i = 0; i < len; i++) { string first = s.substr(0, 1); // 맨 앞의 문자 1개를 문자열로 분리 string sub = s.substr(1, len-1); // 나머지 문자들을 문자열로 분리 s = sub + first; cout << s << endl; } }
C++
복사
4 + 125 + 4 + 77 + 102 등으로 표현된 덧셈식을 문자열로 입력받아 계산하는 프로그램
#include <iostream> #include <string> using namespace std; int main() { string s; cout << "7 + 23 + 5 + 100 + 25 와 같이 덧셈 문자열을 입력하세요." << endl; getline(cin, s, '\n'); // 문자열 입력 int sum = 0; int startIndex = 0; // 문자열 내에 검색할 시작 인덱스 while(true) { int fIndex = s.find('+', startIndex); if (fIndex == -1) { // '+' 문자를 발견할 수 없음 string part = s.substr(startIndex); if (part == "") break; // "2 + 3 + ", 즉 +로 끝나는 경우 cout << part << endl; sum += stoi(part); // 문자열을 수로 변환하여 더하기 break; } int count = fIndex - startIndex; // 서브스트링으로 자를 문자 개수 string part = s.substr(startIndex, count); //startIndex부터 count 개의 문자로 서브스트링 만들기 cout << part << endl; sum += stoi(part); // 문자열을 수로 변환하여 더하기 startIndex = fIndex + 1; // 검색을 시작할 인덱스 전진시킴 } cout << "숫자들의 합은 " << sum; }
C++
복사
&가 입력될 때까지 여러 줄의 영문 문자열을 입력 받고, 찾는 문자열과 대치할 문자열을 각각 입력 받아 문자열을 변경하라
#include <iostream> #include <string> using namespace std; int main() { string s; cout << "여러 줄의 문자열을 입력하세요. 입력의 끝은 &문자입니다." << endl; getline(cin, s, '&'); // 문자열 입력 cin.ignore(); // & 뒤에 따라 오는 <Enter> 키를 제거하기 위한 코드 string f, r; cout << endl << "find: "; getline(cin, f, '\n'); // 검색할 문자열 입력 cout << "replace: "; getline(cin, r, '\n'); // 대치할 문자열 입력 int startIndex = 0; while (true) { int fIndex = s.find(f, startIndex); // startIndex 부터 문자열 f 검색 if (fIndex == -1) break; // 문자열 s의 끝까지 변경하였음 s.replace(fIndex, f.length(), r); // fIndex 부터 문자열 f의 길이만큼 문자열 r로 변경 startIndex = fIndex + r.length(); } cout << s << endl; }
C++
복사