출처 :
- 명품 C++ Programming (저자 황기태)
- 객체지향프로그래밍
객체 포인터
- 객체의 주소 값을 가지는 변수
- 포인터로 멤버를 접근할 때 . 연산자 대신 - > 객체포인터 - > 멤버
Circle donut;
double d = donut.getArea();
// p의 자료형은 Circle *
Circle *p; // 객체에 대한 포인터 선언
p = &donut; // 포인터에 객체 주소 저장
d = p -> getArea(); // 멤버 함수 호출
*포인터로도 private 에는 접근 불가능
p->getArea() == (*p).getArea()
// (*p)는 객체 자체가 된다.
객체 배열, 생성 및 소멸
객체 배열 선언
- 객체 배열을 위한 공간 할당
- 배열의 각 원소 객체마다 생성자 실행
- 매개 변수 없는 생성자가 호출됨
class Circle {
int radius;
public:
Circle(int r) { radius = r; }
double getArea() {
return 3.14 * radius * radius;
}
};
int main() {
Circle waffle(15); // 매개 변수 있는 생성자 Circle(int r)을 호출
Circle circleArray[3]; // 컴파일 오류!! 객체 배열은 매개 변수 "없는" 생성자를 실행해야하는데
} // Circle(int r)이 선언되어 있어 매개 변수 "없는 기본 생성자가 자동 삽입되어 있지 않다.
Circle *p;
p = circleArray; // p는 cicleArray의 첫 요소의 주소값을 담고 있다.
for (int i = 0; i < 3; i++) {
cout << "Circle" << i << "의 면적은 " << circleArray[i].getArea() << endl;
// 윗 줄과 아랫 줄은 같은 결과
cout << "Circle" << i << "의 면적은 " << p->getArea() << endl;
p++; // 객체 요소 하나의 크기만큼 증가한다.
}
객체 배열 생성 및 소멸
선언
- 객체 배열을 위한 공간 할당
- 배열의 각 원소 객체마다 생성자 실행
- c[0]의 생성자, c[1]의 생성자...
- c[0][0], c[0][1], c[1][0] ... 순서
- 매개 변수 없는 생성자 호출 (매개 변수 있는 생성자 호출 불가능)
소멸
- 각 원소 객체마다 “생성의 반대순”으로 소멸
객체 배열 초기화
- 배열의 각 원소 객체당 생성자 지정
Circle circleArray[3] = { Circle(10), Circle(20), Circle() };
// CircleArray[0] 객체가 생성될 때, 생성자 Circle(10) 호출
동적 메모리 할당 및 반환
정적 할당
- 변수 선언을 통해 필요한 메모리 할당
- 많은 양의 메모리는 배열 선언을 통해 할당
동적 할당
- 필요한 양이 예측되지 않는 경우. 프로그램 작성시 할당 받을 수 없음.
- 실행 중에 힙 메모리에 할당
- 메모리가 더 필요한 즉시 힙 heap으로부터 할당
- 힙 : 운영체제가 프로세스(프로그램)의 실행을 시작 시킬 떄 동적 할당 공간으로 준 메모리 공간
c++ 동적 메모리 할당/반환
- new 연산자
- 기본 타입 메모리, 배열, 객체, 객체 배열 할당
- 객체의 동적 생성 - 힙 메모리부터 객체를 위한 메모리 할당 요청
- 객체 할당 시 생성자 호출
- delete 연산자
- new로 할당 받은 메모리 반환 - 안하면 메모리 누수
- 객체의 동적 소멸 → 소멸자 호출 뒤 객체를 힙에 반환
- 생성한 순서와 관계 없이 원하는 순서대로 delete 가능
- 적절치 못한 포인터로 delete 하면 실행 시간 오류 발생
int n; int *p = &n; // 포인터 p가 가리키는 메모리는 동적으로 할당 받은 것이 아님 delete p; // 실행 시간 오류 int *p = new int; delete p; // 정상 delete p; // 실행 시간 오류 - 이미 반환한 메모리를 중복 반환할 수 없음
- 사용 형식
데이터 타입 *포인터변수 = new 데이터타입; // heap에 할당
데이터 타입 *포인터변수 = new 데이터타입(초기값);
delete 포인터 변수; // heap에 할당된 건 포인터 변수로 접근
테이터 타입 *포인터변수 = new 데이터타입 [배열의 크기]; // 동적 배열 할당
// 배열은 동적 할당 시 초기화 불가능
delete [] 포인터 변수;
int *pInt = new int;
Circle *pCircle = new Circle();
delete pInt; // delete 후에도 포인터는 살아있지만 더이상 포인터가 가리키는 곳에 접근하면 안됨
delete pCircle;
#include <iostream>
using namespace std;
int main() {
int *p;
p = new int;
if (!p) {
cout << "메모리 할당할 수 없음";
return 0;
}
*p = 5; // 할당 받은 정수 공간에 5 삽입
int n = *p;
delete p; // 프로그램이 돌아가는 중간에 명시적으로 delete 해주는 게 좋다
};
객체 배열의 사용, 배열의 반환과 소멸자
// 동적으로 생성된 배열도 보통 배열처럼 사용
Circle *pArray = new Circle[3];
pArray[0].setRadius(10);
pArray[1].setRadius(20)'
pArray[2].setRadius(30)'
for (int i = 0; i < 3; i++
cout << pArray[i].getArea();
// 포인터로 배열 접근
pArray->setRadius(10);
(pArray+1)->setRadius(20);
(pArray+2)->setRadius(30);
// 배열 소멸
delete [] pArray;
// pArray[2], [1], [0] 객체의 소멸자 실행
예제 정수형 배열의 동적 할당 및 반환
#include <iostream>
using namespace std;
int main() {
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; // 배열 메모리 반환
}
동적 메모리 할당과 메모리 누수
char n = 'a';
char *p = new char[1024]; // 힙의 char [1024] 주소를 가리킨다.
p = &n; // n을 가리키게 되면서 이전에 할당 받은 char [1024]는
// 반환할 수도 없고 사용하지도 않는 누수 메모리가 된다.
// 프로그램이 종료되면, 운영체제는 누수 메모리를 모두 힙에 반환
this 포인터
- 포인터, 객체 자신 포인터
- 클래스의 멤버 함수 내에서만 사용
- 개발자가 선언하는 변수가 아닌 컴파일러가 선언한 변수
- 멤버 함수에 컴파일러에 의해 묵시적으로 삽입되는 매개 변수
- 각 객체 속의 this는 다른 객체의 this와 다름
class Circle {
int radius;
public:
Circle() { this->radius=1; }
void setRadius(int radius) { this->raadius = radius; }
// Circle의 멤버변수 밖에서 입력한 readius
this 가 필요한 경우
- 매개변수의 이름과 멤버 변수의 이름이 같은 경우
Circle (int radius) {
this->radius = radius;
}
- 멤버 함수가 객체 자신의 주소를 리턴할 때
class Sample {
public:
Sample * f() {
...
return this;
}
}
this의 제약 사항
- 멤버 함수가 아닌 함수에서 this 사용 불가 - 객체와의 관련성이 없음
- static 멤버 함수에서 this 사용 불가 객체가 생기기 전에 static 함수 호출이 있을 수 있기 때문
this 포인터의 실체 - 컴파일러에서 처리
// 개발자가 작성한 클래스
class Sample {
int a;
public:
void setA(int x) {
this->a = x;
}
};
// 컴파일러에 의해 변환된 클래스
class Sample {
...
public:
void setA(Sample *this, int x) {
this->a = x;
}
};
// 객체의 멤버 함수를 호출하는 코드의 변환
ob.setA(5);
ob.setA(&ob, 5); // ob는 객체 자신, &ob는 주소
// ob의 주소가 this 매개변수에 전달됨
String 클래스를 이용한 문자열
C++ 문자열
- C- 스트링
- C++ string 클래스의 객체
String 클래스
- <string> 헤더파일에 선언
- 가변크기의 문자열
- 문자열 복사, 문자열 비교, 문자열 길이 등 다양한 문자열 연산자와 멤버 함수 포함
- 문자열, 스트링, 문자열 객체, string 객체 등으로 혼용
문자열 생성
string str; // 빈 문자열
string address("블라블라");
string copyAdress(address);
char text[] = {'L','O','V','E','\\0'};
string title(text); // "LOVE" 문자열을 가진 title 생성
문자열 숫자 변환 stoi() 함수 이용
string s = "123";
int n = stoi(s);
string 객체의 동적 생성
new/delete를 이용하여 문자열을 동적 생성/반환 가능
string *p = new string("C++"); // 스트링 객체 동적 생성
cout << *p;
p->append(" Great!!");
delete p;
예제 - string 배열 선언과 문자열 키 입력 응용
#include <iostream>
#include <string>
using namespace std;
int main() {
string names[5];
for (int i = 0; i < 5; i++) {
cout << "이름 >> ";
getline(cin, names[i], '\\0');
}
string latter = names[0];
for (int i = 1; i < 5; i++ )
if (latter < names[i])
latter = names[i];
}
밑에 예제 더 있음~~!! ppt 39 부터
'[전공]' 카테고리의 다른 글
[명품 C++] 6장 함수 중복과 static 멤버 (3) | 2022.06.05 |
---|---|
[명품 C++] 05 함수와 참조, 복사 생성자 (6) | 2022.06.05 |
[명품 C++] 03 - 2 생성자 소멸자 구조체 (0) | 2022.06.02 |
[명품 C++] 03 클래스와 객체 (0) | 2022.06.02 |
[명품 C++] 02 C++ 프로그래밍의 기본 (0) | 2022.06.02 |