콘텐츠로 이동

Chapter 4. 객체 포인터

'명품 C++Programming - 황기태' 4장 학습 내용

소스코드

1절. 객체

2절. 동적 할당

3절. 배열의 동적 할당

4절. this

5절. string

1절. 객체

객체 포인터

  • 객체에 대한 포인터
  • C언어의 포인터와 동일
  • 객체의 주소값을 가지는 변수
  • 포인터로 멤버를 접근할 때
  • 객체 포인터 -> 멤버
Circle donut;
double area = donut.getArea();

Circle *p;
// (1) 객체에 대한 포인터 선언

p = &donut;
// (2) 포인터에 객체 주소 저장

d = p->getArea();
// (3) 멤버 함수 호출

Pointer

객체 배열 생성 및 소멸

  • 객체 배열 선언 가능
  • 기본 타입 배열 선언과 형식 동일
    • 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]의 소멸자 실행
  • 예제 2. Circle 클래스 배열 선언 예제
    SourceCodeChecking

  • 예제 2의 설명
    ex4_2

객체 배열 생성 시 기본 생성자 호출

obcon

객체 배열 초기화

  • 객체 배열 초기화 방법
  • 배열의 각 원소 객체 당 생성사 지정하는 방법
Circle circleArray[3] = { Circle(10), Circle(20), Circle() };
  • circleArray[0] 객체가 생성될 때, 생성자 Circle(10) 호출
  • circleArray[1] 객체가 생성될 때, 생성자 Circle(20) 호출
  • circleArray[2] 객체가 생성될 때, 생성자 Circle() 호출

  • 예제 3. 객체 배열 초기화 예제
    SourceCodeChecking

2차원 배열

  • 2차원 배열 선언
    arr2_1

  • 2차원 배열 선언과 초기화
    arr2_2

  • 2차원 배열을 초기화하는 다른 방식
    arr2_3

  • 예제 4. Circle 클래스 2차원 배열 선언 예제
    SourceCodeChecking

2절. 동적 할당

동적 메모리 할당 및 변환

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

new와 delete 연산자

  • C++의 기본 연산자
  • new 연산자의 사용 형식
DataType *pointervalue = new DataType;
  • delete 연산자의 사용 형식
delete pointervalue;
  • new와 delete 연산자의 사용 예시
int *pInt = new int;
// int 타입의 메모리 동적 할당

char *pChar = new char;
// char 타입의 메모리 동적 할당

Circle *pCircle = new Circle;
// Circle 타입의 메모리 동적 할당



delete pInt;
// 할당 받은 정수 공간 반환

delete pInt;
// 할당 받은 문자 공간 반환

delete pInt;
// 할당 받은 객체 공간 반환

기본 탕비의 메모리 동적 할당 및 반환

pointermemory

delete 연산자 주의 사항

  • 적절치 못한 포인터로 delete 하면 실행시간 오류 발생
  • 동적으로 할당받지 않는 메모리 반환 (Error)
int n;
int *p = &n;
delete p;
// 실행 시간 오류 발생

// why ? >> 포인터 p가 가리키는 메모리는 동적으로 할당 받은 것이 아님
// 복사 생성자를 사용한 것(5장 참조)
  • 동일한 메모리 두 번 반환 (Error)
int *p = new int;
delete p;       // 정상적인 메모리 반환
delete p;       // 실행 시간 오류 발생
// why ? >> 이미 반환한 메모리는 중복 반환 불가능

3절. 배열의 동적 할당

배열의 동적 할당 및 반환

  • new와 delete 연산자의 사용 형식
DataType *pointervalue = new DataType[ArrayLength];
// 동적 배열 할당

delete [] pointervalue;
// 배열 반환
  • 그림으로 이해하기 arrpointermemory

  • 예제 6. 정수형 배열의 동적 할당 및 반환 예제
    SourceCodeChecking

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

  • 동적 할당 메모리 초기화
  • 동적 할당 시 초기화
DataType *pointervalue = new DataType(InitialValue);
int *pInt = new int(20);
// 20으로 초기화된 int 타입 할당

char *pChar = new char('a');
// 'a'로 초기화된 char 타입 할당
  • 배열은 동적 할당 시 초기화 불가능
int *pArray = new int[10](20);
int *pArray = new int(20)[10];
// 동적 할당하면서 초기화는 불가능하기 때문에 컴파일 오류 발생
  • delete시 [] 생략
  • 컴파일 오류는 아니지만 비정상적인 반환
int *p = new int[10];
delete p;
// 비정상적인 반환
// delete [] p; 가 올바른 코드

int *q = new int;
delete [] q;
// 비정상적인 반환
// delete q; 가 올바른 코드

객체의 동적 생성 및 반환

ClassName *pointervalue = new ClassName;
ClassName *pointervalue = new ClassName(ConstructorArgumentList);
delete pointervalue;

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

ClassName *pointervalue = new ClassName[ArrayLength];
delete [] pointervalue;
// 포인터 변수가 가리키는 객체 배열 반환
  • 그림으로 이해하기 returnarrayobject

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

  • 동적으로 생성된 배열도 보통 배열처럼 사용
Circle *pArray = new Circle[3];
// 3개의 Circle 객체 배열 동적 생성

pArray[0].setRadius(10);
pArray[1].setRadius(20);
pArray[2].setRadius(30);
// 각각 배열 객체의 setRadius() 멤버 함수를 통해 초기화

for(int i = 0; i < 3; i++)
 cout << pArray[i].getArea() << endl;
// 배열의 i 번째 객체 getArea() 멤버 함수를 차례로 호출
  • 포인터로 배열 접근
pArray->setRadius(10);
// pArray는 pArray 배열의 첫 번째 주소값으로, pArray[0]과 같음

(pArray + 1)->setRadius(20);
(pArray + 2)->setRadius(30);
// 각각 배열 객체의 setRadius() 멤버 함수를 통해 초기화

for(int i = 0; i < 3; i++)
 cout << (pArray + i)->getArea() << endl;
// 배열의 i 번째 객체 getArea() 멤버 함수를 차례로 호출
  • 배열 소멸
delete [] pArray;
// 객체의 소멸자 실행
// 각 원소 객체의 소멸자를 별도로 실행하며 생성의 반대 순서로 소멸됨

// 출력 예시
// pArray[2] 객체의 소멸자 실행       (1)
// pArray[1] 객체의 소멸자 실행       (2)
// pArray[0] 객체의 소멸자 실행       (3)

메모리 할당과 메모리 누수

memory

4절. this

this 포인터

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

this와 객체

this

this가 필요한 경우

  • 매개 변수의 이름과 멤버 변수의 이름이 같은 경우 this2

  • 멤버 함수가 객체 자신의 주소를 리턴할 때

  • 연산자 중복 시에 필요

this3

this의 제약 사항

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

this 포인터의 실체

  • 컴파일러에서 처리 thiscom

5절. string

string 클래스를 이용한 문자열

  • C++ 문자열
  • C-스트링
  • C++ string 클래스의 객체
  • string 클래스
  • C++ 표준 라이브러리
  • 헤더 파일에 선언
#include <string>

using namespace std;
...
  • 가변 크기의 문자열
string str = "I love ";
// str은 'I', ' ', 'l', 'o', 'v', 'e', ' '의 7개 문자로 구성
// 공백도 포함하는 모습 확인 가능

str.append("C++.");
// str은 "I love C++."의 문자열이 됨
// 11개의 문자
...
  • 다양한 문자열 연산을 실행하는 연산자와 멤버 함수 포함
  • 문자열 복사, 문자열 비교, 문자열 길이 등
  • 문자열, 스트링, 문자열 객체, string 객체 등으로 혼용

string 객체 생성 및 입출력

  • 문자열 생성
string str;
// 빈 문자열을 가진 스트링 객체

string address("서울특별시 성북구 삼선동 389");
// 문자열 리터럴로 초기화

string copyAddress(address);
// 위의 스트링 객체 address를 복사한 copyAddress 생성


// C-스트링(char[] 배열)으로부터 스트링 객체 생성
char text[] = {'L', 'O', 'V', 'E', ' ', 'C', '+', '+', '\0'};
string title(text);
// "LOVE C++"의 문자열을 가진 title 생성
  • 문자열 출력 : cout과 << 연산자 사용
cout << address << endl;
// "서울특별시 성북구 삼선동 389"가 출력

cout << title << endl;
// "LOVE C++" 출력
  • 문자열 입력 : cin과 >> 연산자 사용
string name;
cin >> name;
// 공백이 입력되면 하나의 문자열로 입력된 것으로 간주
  • 문자열 숫자 변환 : stoi() 함수 이용 (2011 C++ 표준부터)
string s = "123";
int n = stoi(s);
// n은 정수 123

string 객체의 동적 생성

  • new / delete를 이용하여 문자열을 동적 생성 및 반환 가능
string *p = new string("C++");
// 스트링 객체 동적 생성

cout << *p << endl;
// "C++" 출력

p->append(" Great!");
// p가 가리키는 스트링 : C++ Great!

cout << *p << endl;
// "C++ Great!" 출력

delete p;
// 스트링 객체 반환