객체 포인터와 객체 배열, 객체의 동적 생성
객체 포인터
•
객체에 대한 포인터
◦
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++
복사