'자식 클래스'에 해당되는 글 2건

  1. 2021.01.11 is a / has a
  2. 2020.12.15 클래스 상속

is a / has a

C++ 2021. 1. 11. 18:17

https://modoocode.com/210

 

씹어먹는 C++ - <6 - 2. 가상(virtual) 함수와 다형성>

 

modoocode.com

기반 클래스 = 부모 클래스

파생 클래스 = 자식 클래스

 

 

1. is a

- 모든 상속 관계는 is a라고 볼 수 있음, 이를 뒤 바꾸면 성립되지 않음

- 모든 클래스들의 관계는 is a 로만 표현할 수 없음

- 어떤 클래스들 사이에서는 is a 대신에 has a 관계가 성립되기도 함

 

class Manger(파생 클래스) : public Employee(기반 클래스)

 

- Manager 클래스는 Employee의 모든 기능을 포함한다

- Manager를 Employee라고 봐도 무방

- Manager is a Employee

- Employee는 Manager가 아님

- Manager는 Employee로 부를 수 있지만, Employee는 Manager로 부를 수 없음

 

2. has a

- 자동차는 엔진을 가진다 car has a engine, 자동차는 브레이크를 가진다 car has a brake

 

class car {

 pirvate:

  Engine e;

  Brake b;

}

 

- Employeelist는 Employee와 has a 관계임, employee를 포함하고 있음을 알 수 있음

 

class EmployeeList {

 int alloc_employee; // 할당한 총 직원수

 int current_employee; // 현재 직원 수

 Employee **employee_list; // 직원 데이터

}

 

 

EmployeeList

#include <iostream>

class EmployeeList {
    int alloc_employee; // 할당한 총 직원수
    
    int current_employee; // 현재 직원 수
    int current_manager; // 현재 매니저 수
    
    Employee **employee_list; // 직원 데이터
    Manager **manager_list; // 매니저 데이터
};

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    return 0;
}

위 코드에서 가장 문제 되는 것은 각 클래스 별로 따로 데이터를 보관해야 한다는 것

Employee는 Employee * 가 가리켜야 하고, Manager들은 Manager * 가 가리켜야 함

업 캐스팅은 자유롭게 수행될 수 있음

Employee * 가 Manager 객체를 가리켜도 별 문제가 없다는 것

 

void print_employee_info() {
    int total_pay = 0;
    for (int i = 0; i < current_employee; i++) {
        employee_list[i]->print_info();
        total_pay += employee_list[i]->calculate_pay();
}

employee_list[i]->printf_info()를 하게 되면 무조건 Employee 클래스의 print_info 함수가 호출

employee_list[i]는 Employee 객체를 가리키는 포인터이기 때문에 자신이 가리키는 객체가 Employee 객체라고 생각함

Manager 객체와 Employee 객체 모두 Employee* 가 가리키도록 하였으므로,

만일 employee_list[i] 가 가리키는 것이 Manager 객체 일 때, Manager의 print_info함수가 아니라 

Employee의 print_info함수가 호출되서 다른 결과를 냄

마찬가지로 calculate_pay 함수도 Manager의 calculate_pay 가 호출되어야 하는데 

Employee의 calculate_pay가 호출되어서 틀린 결과가 나옴

 

#include <iostream>
#include <string>

using namespace std;

class Employee {
protected:
    string name;
    int age;
    
    string position; // 직책 (이름)
    int rank; // 순위 (값이 클 수록 높은 순위)
public:
    Employee(string name, int age, string position, int rank)
    : name(name), age(age), position(position), rank(rank) {}
    
    // 복사 생성자
    Employee(const Employee& employee) {
        name = employee.name;
        age = employee.age;
        position = employee.position;
        rank = employee.rank;
    }
    
    // 디폴트 생성자
    Employee() {}
    
    void print_info() {
        cout << name << " (" << position << " , " << age << ") ==> " << calculate_pay() << "만원" << endl;
    }
    int calculate_pay() { return 200 + rank * 50; }
};

class Manager : public Employee {
    int year_of_service;
public:
    Manager(string name, int age, string position, int rank, int year_of_service)
    : year_of_service(year_of_service), Employee(name, age, position, rank) {}
    
    // 복사 생성자
    Manager(const Manager& manager)
    : Employee(manager.name, manager.age, manager.position, manager.rank) {
        year_of_service = manager.year_of_service;
    }
    
    // 디폴트 생성자
    Manager() : Employee() {}
    
    int calculate_pay() { return 200 + rank * 50 + year_of_service; }
    void print_info(){
        cout << name << " (" << position << " , " << age << " , " << year_of_service << "년차) ==> " << calculate_pay() << "만원" << endl;
    }
};

class EmployeeList {
    int alloc_employee; // 할당한 총 직원 수
    int current_employee; // 현재 직원 수
    Employee** employee_list; // 직원 데이터
public:
    EmployeeList(int alloc_employee) : alloc_employee(alloc_employee) {
        employee_list = new Employee*[alloc_employee];
        
        current_employee = 0;
    }
    void add_employee(Employee* employee) {
        // current_employee 보다 alloc_employee가 더 많아지는 경우
        // 반드시 재할당을 해야 하지만 여기서는 최대한 단순하게 생각해서
        // alloc_employee는 언제나 current_employee 보다 크다고 생각함
        // 즉 할당된 크기는 현재 총 직원수 보다 많음
        employee_list[current_employee] = employee;
        current_employee++;
    }
    int current_employee_num() { return current_employee; }
    
    void print_employee_info() {
        int total_pay = 0;
        for (int i = 0; i < current_employee; i++) {
            employee_list[i]->print_info();
            total_pay += employee_list[i]->calculate_pay();
        }
        cout << "총 비용 : " << total_pay << "만원 " << endl;
    }
    ~EmployeeList() {
        for (int i = 0; i < current_employee; i++) {
            delete employee_list[i];
        }
        delete[] employee_list;
    }
};


int main(int argc, const char * argv[]) {
    EmployeeList emp_list(10);
    emp_list.add_employee(new Employee("khon01", 10, "평사원", 1));
    emp_list.add_employee(new Employee("khon02", 20, "평사원", 1));
    emp_list.add_employee(new Manager("khon03", 30, "부장", 7, 12));
    emp_list.add_employee(new Manager("khon04", 40, "과장", 4, 15));
    emp_list.add_employee(new Manager("khon05", 28, "차장", 5, 13));
    emp_list.add_employee(new Employee("khon06", 52, "대리", 2));
    emp_list.add_employee(new Employee("khon07", 24, "인턴", -2));
    emp_list.print_employee_info();

    return 0;
}

전부다 Employee의 print_info와 calculate_pay 함수가 호출되서 원래 결과와 달라짐

'C++' 카테고리의 다른 글

예제1  (0) 2021.01.21
static  (0) 2021.01.12
C++ 문제 풀이  (0) 2021.01.11
소켓 프로그래밍 함수와 Winsock2  (0) 2020.12.17
소켓 프로그래밍의 개요  (0) 2020.12.17
Posted by khon98
,

클래스 상속

C++ 2020. 12. 15. 16:10

상속

- 상속은 객체 지향 프로그래밍의 주요한 특성 중 하나

- 현실 세계에서의 상속의 개념을 프로그래밍으로 그대로 가져와 사용할 수 있음

- 이를 통해 프로그램의 논리적 구조를 계층적으로 구성할 수 있음

- 흔히 자식이 부모의 속성을 물려받듯이 자식 클래스가 부모 클래스의 속성을 그대로 물려받아 사용할 수 있음

- 그러므로 상속을 활용하여 소스코드의 재사용성을 늘일 수 있음

- 자식 클래스는 파생 클래스라고도 불리며 부모 클래스의 모든 속성을 물려 받음

- 자식 클래스는 콜론(:)을 활용하여 부모 클래스와 연결될 수 있음

 

* 부모 클래스 정의하기

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

class Person {
private:
    string name;
public:
    Person(string name): name(name) {}
    string getName() {
        return name;
    }
    void showName(){
        cout << "이름: " << getName() << '\n';
    }
};

 

* 자식 클래스 정의 및 사용하기

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

class Person { // 부모 클래스
private:
    string name;
public: // 생성자
    Person(string name) : name(name) {} // 멤버 변수 name을 전달 받은 매개 변수 name으로 초기화
    string getName() {
        return name;
    }
    void showName() {
        cout << "이름: " << getName() << '\n';
    }
};

class Student  : Person {
private:
    int studentID; // 멤버 변수 name은 Person으로 부터 물려 받음
public:
    Student(int studentID, string name) : Person(name) {
        this->studentID = studentID;
    }
    void show(){
        cout << "학생 번호: " << studentID << '\n';
        cout << "학생 이름: " << getName() << '\n';
    }
};

int main(void) {
    Student student(1, "khon");
    student.show();
    system("pause");
    return 0;
}

 

생성자와 소멸자

- 자식 클래스의 인스턴스를 만들 때  가장 먼저 부모 클래스의 생성자가 호출, 이후 자식 클래스의 생성자가 호출

- 자식 클래스의 수명이 다했을 때는 자식 클래스의 소멸자가 먼저 호출된 이후에 부모 클래스의 소멸자가 호출

 

오버 라이딩

- 부모 클래스에서 정의된 함수를 무시하고 자식 클래스에서 동일한 이름의 함수를 재정의하는 문법

- 오버 라이딩을 적용한 함수의 원형은 기존의 함수와 동일한 매개 변수를 전달 받음

class Student  : Person {
private:
    int studentID; // 멤버 변수 name은 Person으로 부터 물려 받음
public:
    Student(int studentID, string name) : Person(name) {
        this->studentID = studentID;
    }
    void show(){
        cout << "학생 번호: " << studentID << '\n';
        cout << "학생 이름: " << getName() << '\n';
    }
    void showName() {
        cout << "학생 이름: " << getName() << '\n';
    }
};

int main(void) {
    Student student(1, "khon");
    student.showName();
    system("pause");
    return 0;
}

 

다중 상속

- 여러 개의 클래스로부터 멤버를 상속받는 것을 말함

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

class Temp {
public:
    void showTemp() {
        cout << "임시 부모 클래스.\n";
    }
};

class Person {
private:
    string name;
public: // 생성자
    Person(string name) : name(name) {}
    string getName() {
        return name;
    }
    void showName() {
        cout << "이름: " << getName() << '\n';
    }
};

class Student  : Person, public Temp {
private:
    int studentID;
public:
    Student(int studentID, string name) : Person(name) {
        this->studentID = studentID;
    }
    void show(){
        cout << "학생 번호: " << studentID << '\n';
        cout << "학생 이름: " << getName() << '\n';
    }
    void showName() {
        cout << "학생 이름: " << getName() << '\n';
    }
};

int main(void) {
    Student student(1, "khon");
    student.showName();
    student.showTemp();
    system("pause");
    return 0;
}

 

다중 상속의 한계

- 여러 개의 부모 클래스에 동일한 멤버가 존재할 수 있음

- 하나의 클래스를 의도치 않게 여러 번 상속받을 가능성이 있음

 

 

- C++의 클래스 상속은 객체 지향 프로그래밍의 중요한 키워드

- 상속의 원리를 활용하여 소스코드의 재사용성을 증대시킬 수 있음

'C++' 카테고리의 다른 글

캡슐화 기법  (0) 2020.12.15
오버로딩  (0) 2020.12.15
생성자와 소멸자  (0) 2020.12.15
C++의 클래스  (0) 2020.12.14
C언와 C++ 비교  (0) 2020.12.14
Posted by khon98
,