inheritance와 hierarchy 둘의 뉘앙스 차이
- inheritance는 “관계 하나”,
누가 누구에게서 뭘 직접 물려받는 순간에 집중- hierarchy는 “전체 구조”,
어떤 존재가 위에 있고, 그 아래로 어떤 질서가 있는지에 집중
상속의 개념: 자식이 부모로부터 재산을 물려받는 개념
inheritance in opp
#include <iostream>
using namespace std;
class Employee {
public:
Employee() {
strName = NULL;
strAddr = NULL;
}
~Employee() {
delete[] strName;
delete[] strAddr;
}
Employee(const char* pName, const char* pAddr) {
strName = new char[strlen(pName) + 1];
strAddr = new char[strlen(pAddr) + 1];
strcpy(strName, pName);
strcpy(strAddr, pAddr);
strName[strlen(pName) + 1] = '\0';
strName[strlen(pAddr) + 1] = '\0';
}
void DisplayEmployee() {
cout << "이름: " << strName << endl;
cout << "주소: " << strAddr << endl;
}
private:
char* strName;
char* strAddr;
};
int main () {
Employee emp("Kim", "seoul");
emp.DisplayEmployee();
return 0;
}
strlen()
문자열 표준 함수strcpy()
C++에서 클래스의 자식(즉, 파생 클래스)을 정의할 때 사용하는 :
(콜론)은 "상속 지정자"(Inheritance Specifier)라고 부릅니다.
(in JS/JAVA 는 콜론이 아닌 extends
)
#include <iostream>
using namespace std;
class Employee {
public:
Employee() {
strName = NULL;
strAddr = NULL;
}
~Employee() {
delete[] strName;
delete[] strAddr;
}
Employee(const char* pName, const char* pAddr) {
strName = new char[strlen(pName) + 1];
strAddr = new char[strlen(pAddr) + 1];
strcpy(strName, pName);
strcpy(strAddr, pAddr);
strName[strlen(pName) + 1] = '\0';
strName[strlen(pAddr) + 1] = '\0';
}
void DisplayEmployee() {
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
protected:
char* strName;
char* strAddr;
};
class Regular : Employee {
public:
Regular() {}
Regular(char* pName, char* pAddr, double pSalary) {
strName = new char[strlen(pName) + 1];
strAddr = new char[strlen(pAddr) + 1];
strcpy(strName, pName);
strcpy(strAddr, pAddr);
salary = pSalary;
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
~Regular() {}
double PayCheck() {
return salary;
delete[] strName;
delete[] strAddr;
}
private:
double salary;
};
class Temporary : Employee {
public:
Temporary() {}
Temporary(const char* pName, const char* pAddr, double pDailyPay, int pDays) {
strName = new char[strlen(pName) + 1];
strAddr = new char[strlen(pAddr) + 1];
strcpy(strName, pName);
strcpy(strAddr, pAddr);
dailyPay = pDailyPay;
days = pDays;
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
~Temporary() {}
double PayCheck() {
return days * dailyPay;
delete[] strName;
delete[] strAddr;
}
private:
double dailyPay;
int days;
};
int main() {
Employee emp("Kim", "seoul");
emp.DisplayEmployee();
Regular rgl("park", "Deagu", 300);
cout << "ㄴ 정규직원 급여: " << rgl.PayCheck() << endl;
Temporary tmp("choi", "Bundang", 20, 30);
cout << "ㄴ 계약직원 급여: " << tmp.PayCheck() << endl;
return 0;
}
protected
접근 지정자란? C++에서 protected
는 객체지향 프로그래밍의 상속(inheritance) 개념과 관련이 깊은 접근 지정자(access specifier)야. 일반적으로 클래스 멤버(변수와 함수)는 private
, protected
, public
으로 접근 범위를 설정하는데, protected
는 private과 public의 중간 정도의 역할을 해.protected
의 특징:protected
멤버는 private
멤버처럼 해당 클래스 내부에서는 자유롭게 접근할 수 있어.private
멤버는 자식 클래스에서 접근할 수 없지만,protected
멤버는 자식 클래스에서 직접 접근할 수 있어.public
과 달리, 클래스 외부에서는 직접 접근할 수 없어.#include <iostream>
using namespace std;
class Employee {
public:
Employee() {
strName = NULL;
strAddr = NULL;
}
~Employee() {
delete[] strName;
delete[] strAddr;
}
Employee(const char* pName, const char* pAddr) {
strName = new char[strlen(pName) + 1];
strAddr = new char[strlen(pAddr) + 1];
strcpy(strName, pName);
strcpy(strAddr, pAddr);
strName[strlen(pName) + 1] = '\0';
strName[strlen(pAddr) + 1] = '\0';
}
void DisplayEmployee() {
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
protected:
char* strName;
char* strAddr;
};
class Regular : Employee
{
public:
Regular() {
}
Regular(char* pName, char* pAddr, double pSalary) : Employee(pName, pAddr)
{
salary = pSalary;
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
~Regular() {
}
double PayCheck() {
return salary;
}
private:
double salary;
};
class Temporary : Employee
{
public:
Temporary() {
}
Temporary(const char* pName, const char* pAddr, double pDailyPay, int pDays) : Employee(pName, pAddr) {
dailyPay = pDailyPay;
days = pDays;
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
~Temporary() {
}
double PayCheck() {
return days * dailyPay;
}
private:
double dailyPay;
int days;
};
int main () {
Employee emp("Kim", "seoul");
emp.DisplayEmployee();
Regular rgl("park", "Deagu", 300);
cout << "ㄴ 정규직원 급여: "<< rgl.PayCheck() << endl;
Temporary tmp ("choi", "Bundang", 20, 30);
cout << "ㄴ 계약직원 급여: " << tmp.PayCheck() << endl;
return 0;
}
같은 위치에서 생성과 소멸이 되는 것이 코드에 있어서 중요
오버라이딩 조건으로 알 수 있듯이 형태는 동일하고 조건만 달라지는 상속의 형태이다.
code - SalesMan 추가하기
#include <iostream>
using namespace std;
class Employee {
public:
Employee() {
strName = NULL;
strAddr = NULL;
}
~Employee() {
delete[] strName;
delete[] strAddr;
}
Employee(const char* pName, const char* pAddr) {
strName = new char[strlen(pName) + 1];
strAddr = new char[strlen(pAddr) + 1];
strcpy(strName, pName);
strcpy(strAddr, pAddr);
strName[strlen(pName) + 1] = '\0';
strName[strlen(pAddr) + 1] = '\0';
}
void DisplayEmployee() {
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
protected:
char* strName;
char* strAddr;
};
class Regular : Employee
{
public:
Regular() {
}
Regular(char* pName, char* pAddr, double pSalary) : Employee(pName, pAddr)
{
salary = pSalary;
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
~Regular() {
}
double PayCheck() {
return salary;
}
private:
double salary;
};
class SalesMan : public Regular
{
public:
SalesMan(){}
~SalesMan(){}
SalesMan(char* pName, char* pAddr, double pSalary, double allowance)
:Regular(pName, pAddr, pSalary)
{
this->allowance = allowance;
}
double Paycheck() {
return Regular::PayCheck() + allowance;
}
private:
double allowance;
};
class Temporary : Employee
{
public:
Temporary() {
}
Temporary(const char* pName, const char* pAddr, double pDailyPay, int pDays) : Employee(pName, pAddr) {
dailyPay = pDailyPay;
days = pDays;
cout << "이름: " << strName << ", 주소: " << strAddr << endl;
}
~Temporary() {
}
double PayCheck() {
return days * dailyPay;
}
private:
double dailyPay;
int days;
};
int main () {
Employee emp("Kim", "seoul");
emp.DisplayEmployee();
Regular rgl("park", "Deagu", 300);
cout << "ㄴ 정규직원 급여: "<< rgl.PayCheck() << endl;
Temporary tmp ("choi", "Bundang", 20, 30);
cout << "ㄴ 계약직원 급여: " << tmp.PayCheck() << endl;
SalesMan slm("Kim", "Busan", 300, 100);
cout << "ㄴ 영업사원 급여: " << slm.PayCheck() << endl;
return 0;
}
우선 코드의 구조를 파악해보자
Regular rgl("park", "Deagu", 300);
cout << "ㄴ 정규직원 급여: "<< rgl.PayCheck() << endl;
Temporary tmp ("choi", "Bundang", 20, 30);
cout << "ㄴ 계약직원 급여: " << tmp.PayCheck() << endl;
SalesMan slm("Kim", "Busan", 300, 100);
cout << "ㄴ 영업사원 급여: " << slm.PayCheck() << endl;
자식 객체를 부모 객체에 주소값을 전달한다. 아래의 결과는 어떻게 될까
Employee* emp = (Employee*)&rgl;
cout << emp->PayCehck() << endl;
결과
> 0
자식의 객체를 부모객체에게 넘겨도 적용되지 않고 타입을 기준으로 타입의 멤버를 호출합니다.
객체를 넘겼을 때, 받은 객체의 멤버를 호출하고 싶다면..
📚 reference
- book - C++ 프로그래밍과 STL (이창현)
- Photo by Laura Fuhrman on Unsplash