this
this 키워드
클래스 멤버 함수는 this라는 키워드를 통해 자기 자신을 인스턴스(포인터 타입)를 가져올 수 있다.
클래스 멤버 함수를 호출하기 위해서는 호출한 주체인 어떤 클래스 인스턴스가 존재하게 되는데 그 호출 주체를 this라고 한다.
예시코드
class student {
public:
int stdno;
char name[20];
int gender; // 0 = 남자 1 = 여자
student(int stdno, const char* n, int g) {
this->stdno = stdno;
strcpy(name, n);
gender = g;
}
void printstudent() {
printf("학생 번호%d\n", stdno);
printf("학생 이름:%s\n", name);
printf("성별 %s\n", gender == 0 ? "남자" : "여자");
}
};
this-> 를 쓰고 this->stdno에 있는 stdno에 커서를 올려보면 = stdno;가 되있는 부분은 파란불이 안들어올 것이다.
인스턴스(Instance)
클래스는 정의만으로는 존재할 수 없다. 그냥 초안일 뿐이다. 우리가 여지껏 '클래스의 변수' 라고 말해왔던 것을 클래스 인스턴스라고 생각하면 편하다.
이 두개도 인스턴스다
student s = student <- 함수 영역에 있는 인스턴스
student* ps = new student <- Heap 영역에 있는 인스턴스
소멸자(Destructor)
클래스는 소멸자(Destructor)를 통해 메모리에서 해제될 때의 행동을 지정해줄 수 있다. 이를 소멸자라고 한다.
소멸자는 ~클래스명() 으로 선언할 수 있으며, 소멸자도 리턴타입이 존재하지 않는다.
예시 코드
class student {
public:
int stdno;
char name[20];
int gender; // 0 = 남자 1 = 여자
student(int stdno, const char* n, int g) {
this->stdno = stdno;
strcpy(name, n);
gender = g;
}
~student() {
}
void printstudent() {
printf("학생 번호%d\n", stdno);
printf("학생 이름:%s\n", name);
printf("성별 %s\n", gender == 0 ? "남자" : "여자");
}
};
정적 할당된 함수에서는 소멸자가 호출 될 것이다.
예시 코드
#include "Header.h"
class student {
public:
int stdno;
char name[20];
int gender; // 0 = 남자 1 = 여자
student(int stdno, const char* n, int g) {
this->stdno = stdno;
strcpy(name, n);
gender = g;
}
~student() {
printf("%s의 소멸자 호출", name);
}
void printstudent() {
printf("학생 번호%d\n", stdno);
printf("학생 이름:%s\n", name);
printf("성별 %s\n", gender == 0 ? "남자" : "여자");
}
};
int main() {
student s = student(1234, "이혜성", 0);
s.printstudent();
/*student* ps = new student(3456, "당혜성", 1);
ps->printstudent();*/
return 0;
}
이러면 소멸자 호출이 나올것이다.
반대로 동적으로 할당된 함수에서는 호출이 안될것이다.
코드
#include "Header.h"
class student {
public:
int stdno;
char name[20];
int gender; // 0 = 남자 1 = 여자
student(int stdno, const char* n, int g) {
this->stdno = stdno;
strcpy(name, n);
gender = g;
}
~student() {
printf("%s의 소멸자 호출", name);
}
void printstudent() {
printf("학생 번호%d\n", stdno);
printf("학생 이름:%s\n", name);
printf("성별 %s\n", gender == 0 ? "남자" : "여자");
}
};
int main() {
/*student s = student(1234, "이혜성", 0);
s.printstudent();*/
student* ps = new student(3456, "당혜성", 1);
ps->printstudent();
return 0;
}
이 뜻은 정적으로 할당된 함수에서는 제대로 삭제가 됐다는 뜻인데, 동적으로 할당된 함수는 제대로 삭제가 안되었단 뜻이다. 그래서 delete 라는 키워드를 사용한다.
예시 코드
int main() {
/*student s = student(1234, "이혜성", 0);
s.printstudent();*/
student* ps = new student(3456, "당혜성", 1);
ps->printstudent();
delete ps;
return 0;
}
소멸자 호출의 필요성
모든 동적 메모리를 수동으로 관리해줘야 하는 c++의 특성상 클래스 멤버 변수에 동적 메모리 할당된 개체가 있다고 할 경우, 소멸자에서 처리하지 않으면 하나하나 클래스 외부에 delete 전에 메모리를 해제해야 한다.
이는 굉장히 불편함과 불합리함을 초래하게 되는데, 이를 해결할 수 있는 것이 소멸자이다.
예를 들어보자.
지금 우리가 char name[20]; 정적으로 20개인 배열을 만들었는데,
만약에 우리가 char* name; 동적인 형태로 만든다고 생각해보자.
예시 코드
int stdno;
char* name;
int gender; // 0 = 남자 1 = 여자
student(int stdno, const char* n, int g) {
this->stdno = stdno;
strcpy(name, n);
gender = g;
}
이렇게 하면 strcpy를 사용할 수없다. 메모리를 초기화 해보자.
name = new char[20]; 이렇게 해도 낭비되는 공간이 있어서 싫을 수 있다.
name = new char[strlen(n) + 1]; strlen은 null 문자를 제외한 길이를 나타내지만
+1 까지 해서 null 문자까지 센다.
그럼 문자열과 딱 맞는 배열로 만들어져서 호출하게 된다.
그런데 동적 할당이 되어있기 때문에 해제를 해야한다.
근데 우리가 해제하는 시점을 잘 잡을 수 없을 뿐더러, 대부분의 사람들은 못잡는다.
~student() {
printf("%s의 소멸자 호출", name);
delete[] name;
}
그래서 이렇게 하는게 낫다.
연습
어느 회사는 사원 관리 시스템이 있다.
이 출근관리 시스템은 관리자에 의해 사원을 입력받아 등록할 수 있으며, 사원은 각각 사원번호, 이름, 성별, 직급 이라는 속성을 가지고 있다.
관리자는 모든 사원을 한번에 볼 수 있고, 사원은 퇴사시 관리자에 의해 삭제될 수 있다.
삭제는 사원번호를 입력받아 퇴사처리를 할 수 있따.
사원번호는 시스템에 의해 자동으로 관리되며, 사원번호가 관리되는 방법은 자유롭게 구현할 수 있다.
나는 이거 어려워서 따라 쳤다
헤더코드
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <cstdio>
int number_counter = 1;
class employee {
public:
int no;
char name[20];
int gender;
char rank[20];
employee(char* name, int gender, char* rank) {
strcpy(this->name, name);
this->gender = gender;
strcpy(this->rank, rank);
this->no = number_counter;
number_counter++;
}
void printinfo() {
printf("사원 번호:%d\n",no);
printf("사원 이름:%s\n", name);
printf("사원 성별:%s\n", gender == 1 ? "남성" : "여성");
printf("사원 직급:%s\n", rank);
}
};
int getint(const char* prompt);
char* getString(const char* prompt);
소스코드
#define _CRT_SECURE_NO_WARNINGS
#include "mainHeader.h"
int main() {
employee* emp[100];
int count = 0;
while (true) {
printf("명령 입력\n");
printf("1. 사원 보기\n");
printf("2. 사원 추가\n");
printf("3. 사원 삭제\n");
printf("4. 프로그램 종료\n");
fseek(stdin, 0, SEEK_END);
int input;
scanf("%d", &input);
if (input == 1) {
for (int i = 0; i < count; i++) {
emp[i]->printinfo();
}
}
else if (input == 2) {
char* name= getString("사원명 입력:\n");
int gender = getint("성별 입력(1. 남성 2. 여성)");
char* rank = getString("직급을 입력:");
employee* e = new employee(name, gender, rank);
delete[] name;
delete[] rank;
emp[count] = e;
count++;
}
else if (input == 3) {
int number = getint("사원 번호 입력:\n");
int deletedinedex = -1;
for (int i = 0; i < count; i++) {
if (number == emp[i]->no) {
delete emp[i];
deletedinedex = i;
break;
}
}
if (deletedinedex >= 0) {
for (int i = deletedinedex; i < count; i++) {
emp[i] = emp[i + 1];
}
}
count--;
printf("삭제 완료");
}
else if (input == 4) {
printf("프로그램 종료\n");
break;
}
else {
printf("올바르지 않은 입력\n");
}
}
return 0;
}
int getint(const char* prompt){
int input;
printf("%s", prompt);
fseek(stdin, 0, SEEK_END);
scanf("%d", &input);
return input;
}
char* getString(const char* prompt) {
char* input = new char[100];
printf("%s", prompt);
fseek(stdin, 0, SEEK_END);
scanf("%99[^\n]s", input);
return input;
}
'C언어 공부' 카테고리의 다른 글
C++ 기초 - 5 오버라이드 / 오버로드 (0) | 2025.03.16 |
---|---|
C++ 기초 - 4 클래스 상속 / 접근지정자 (0) | 2025.03.16 |
C++ 기초 - 2 클래스 멤버 / 생성자 (0) | 2025.03.15 |
C++ 기초 - 1 객체지향 첫걸음 (0) | 2025.03.15 |
C언어 공부의 자료 출처 (0) | 2025.03.14 |