Oval a;
a.show(); // 객체 a의 show() 메서드 직접 호출
Oval* p = &a;
p->show(); // 포인터 p를 통해 show() 메서드 호출
(*p).show(); // 포인터 p의 간접 참조를 통해 show() 메서드 호출
Oval& ref = a;
ref.show(); // 참조 ref를 통해 show() 메서드 호출
참조는 직접적으로 주소 연산을 할 수 없다.
int arr[5] = {1, 2, 3, 4, 5};
'1. 참조를 사용한 접근'
int& ref = arr[0];
ref++; // ref는 단순히 arr[0]에 대한 참조이므로, 이는 arr[0]의 값을 증가시킴
ref+1; // 이 경우는 단순히 arr[0]의 값에 1을 더하는 것과 같음 (값 자체의 연산)
'2. 포인터를 사용한 접근'
int* ptr = &arr[0];
ptr++; // ptr은 이제 arr[1]을 가리킴 (주소의 증가)
'3. 포인터를 사용하여 배열의 다른 요소로 이동'
for (int i = 0; i < 5; i++) {
std::cout << *(ptr + i) << " "; // 출력: 2 3 4 5 (ptr이 arr[1]을 가리키고 시작하므로)
}
this와 *this의 차이this: 객체 자신의 주소를 가리키는 포인터 (ClassName*)*this: this 포인터가 가리키는 객체 자체 (ClassName&)int x = 3;
int* p = &x; //p = 논리주소, *p = 3
return this;와 return *this;의 차이return this;: 현재 객체 자신의 주소를 반환 (반환 타입: ClassName*) 주로 포인터로 객체를 반환할 때 사용return *this;: 현재 객체 자신을 반환 (반환 타입: ClassName&) 주로 메서드 체이닝이나 객체의 참조를 반환할 때 사용class MyClass {
public:
MyClass(int value) : value(value) {}
MyClass* getThis() {
return this; // 객체 자신의 주소를 반환
}
MyClass& getReference() {
return *this; // 객체 자신을 반환
}
};
#include <iostream>
class MyClass {
public:
MyClass& setValue(int value) {
this->value = value;
return *this; // 객체 자신을 반환하여 메서드 체이닝을 가능하게 함
}
void show() const {
std::cout << "Value: " << value << std::endl;
}
private:
int value;
};
int main() {
MyClass obj;
obj.setValue(10).setValue(20).setValue(30); // 메서드 체이닝
obj.show(); // 출력: Value: 30
return 0;
}
이 예제에서 setValue 메서드는 객체 자신을 반환함으로써 연속적인 메서드 호출(메서드 체이닝)을 가능하게 한다. return *this;를 사용하면 객체의 참조를 반환하여 이러한 패턴을 구현할 수 있다.
#include <iostream>
using namespace std;
class Oval {
int width, height;
public:
Oval() : width(1), height(1) {} // 기본 생성자
Oval(int w, int h) : width(w), height(h) {} // 매개변수가 있는 생성자
void show() {
cout << "width = " << width << ", height = " << height << endl;
}
};
int main() {
'1. 기본 생성자를 사용한 초기화'
Oval arr1[3];
for (int i = 0; i < 3; ++i) arr1[i].show();
'2. 매개변수가 있는 생성자를 사용한 초기화'
Oval arr2[3] = {Oval(1, 2), Oval(3, 4), Oval(5, 6)};
for (int i = 0; i < 3; ++i) arr2[i].show();
'3. 복사 생성자를 사용한 초기화'
Oval obj(7, 8);
Oval arr3[3] = {obj, obj, obj};
for (int i = 0; i < 3; ++i) arr3[i].show();
'4. 동적 할당과 기본 생성자를 사용한 초기화'
Oval* arr4 = new Oval[3];
for (int i = 0; i < 3; ++i) arr4[i].show();
delete[] arr4;
'5. 동적 할당과 매개변수가 있는 생성자를 사용한 초기화'
Oval* arr5 = new Oval[3]{Oval(1, 2), Oval(3, 4), Oval(5, 6)};
for (int i = 0; i < 3; ++i) arr5[i].show();
delete[] arr5;
return 0;
}
| 항목 | 스택 할당 | 힙 할당 |
|---|---|---|
| 코드 예시 | Oval arr[3]; | Oval* arr = new Oval[3]; |
int *p = x; | int *p = new int(3); //힙에 동적으로 int 값 3 할당 | |
| 사용 용도 | 비교적 작은 크기의 고정 배열 | 큰 배열 또는 동적으로 크기를 결정해야 할 때 |
| 메모리 관리 | 자동 해제 | 수동 해제 (delete[] arr;) |
| 할당 크기 제한 | 제한 있음 (스택 크기 제한) | 제한 적음 (힙은 더 큰 메모리 할당 가능) |
| 할당/해제 속도 | 빠름 | 상대적으로 느림 |
| 수명 | 함수 또는 블록이 끝나면 자동 해제 | 명시적으로 해제 전까지 유지 |


키보드에서 원의 개수를 입력받고, 그 개수만큼 원의 이름과 반지름을 입력받는 프로그램.
#include "Circle.h"
#include "CircleManager.h"
#include <iostream>
using namespace std;
int main() {
cout << "원의 개수 : ";
int n;
cin >> n;
CircleManager* man = new CircleManager(n);
man->run();
delete man;
}
#ifndef CIRCLE_H
#define CIRCLE_H
#include <string>
using namespace std; //std::string을 사용하기 위해 미리 선언. string은 std namespace에 존재.
class Circle {
string name; //string() 생성자 호출
int radius;
public:
void setCircle(string name, int radius); //Circle 객체의 이름과 반지름을 설정하는 함수
double getArea();
string getName() { return name; } //inline으로 정의.
};
#endif
#ifndef CIRCLEMANAGER_H
#define CIRCLEMANAGER_H
#include <string>
using namespace std;
class Circle; //#include "Circle.h"와 동일
class CircleManager {
Circle* p;
int size;
void searchByName(string name); //교재랑 다름!!
void searchByArea(int minArea);
public:
CircleManager(int size);
~CircleManager(); //왜 소멸자가 필요한가? 동적할당한 메모리를 해제하기 위해. 항상 동적할당한 메모리는 해제해야 한다.
void run();
};
#endif
#include "Circle.h"
#include <iostream>
using namespace std;
void Circle::setCircle(string name, int radius) {
this->name = name;
this->radius = radius;
}
double Circle::getArea(){
return 3.14*radius*radius;
}
#include "CircleManager.h"
#include "Circle.h"
#include <iostream>
using namespace std;
CircleManager::CircleManager(int size) {
p = new Circle[size];
this->size = size;
for(int i = 0; i < size; i++) {
string name;
int radius;
cout << "원 " << i+1 << "의 이름과 반지름 >> ";
cin >> name >> radius;
p[i].setCircle(name, radius);
}
};
void CircleManager::run() {
cout << "검색하고자 하는 원의 이름 >> ";
string name;
cin >> name;
searchByName(name);
cout << "최소 면적을 정수로 입력하세요 >> ";
int minArea;
cin >> minArea;
cout << minArea << "보다 큰 원을 검색합니다." << endl;
searchByArea(minArea);
cout << "계속 >> (yes) >> ";
string res;
cin >> res;
if (res != "yes") {
run();
}
}
CircleManager::~CircleManager() {
delete[] p;
}
void CircleManager::searchByName(string name) {
// cout << "검색하고자 하는 원의 이름 >> ";
// string name;
// cin >> name;
bool found = false;
for(int i = 0; i < size; i++) {
if(p[i].getName() == name) { //발견
cout << name << "의 면적은 " << p[i].getArea() << endl;
found = true;
break;
}
}
if(found == false)
cout << name << "인 원을 찾을 수 없습니다." << endl;
}
void CircleManager::searchByArea(int minArea) {
for (int i=0; i<size; i++) {
if (p[i].getArea() > minArea) //발견
cout << p[i].getName() << "의 면적은 " << p[i].getArea() << ", ";
}
}