Computer-Science

Polymorphism

Contents

  1. Introduction
  2. Polymorphism ์‚ฌ๋ก€
  3. ํ•ธ๋“ค์˜ ์ž๋ฃŒํ˜•์— ์˜ํ•œ ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ํ˜ธ์ถœ (without Polymorphism)
  4. Polymorphism ๊ตฌํ˜„ (๊ฐ€์ƒ ํ•จ์ˆ˜์— ์˜ํ•œ ๋™์  ๋ฐ”์ธ๋”ฉ)
  5. Abstract Classes and Pure Virtual Functions
  6. Case Study: Payroll System Using Polymorphism

1. Introduction

ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ vs. ํ•จ์ˆ˜ ์˜ค๋ฒ„๋ผ์ด๋”ฉ

ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ (Overloading)

์˜ค๋ฒ„๋กœ๋”ฉ์€ ๊ฐ™์€ ํ•จ์ˆ˜๋ผ๋„ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ๋‹ค๋ฅด๋ฉด ์–ผ๋งˆ๋“ ์ง€ ์ •์˜ํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•จ์ˆ˜ ์˜ค๋ฒ„๋ผ์ด๋”ฉ (Overriding)

์ƒ์† ๊ด€๊ณ„์— ์žˆ๋Š” ํด๋ž˜์Šค ๊ฐ„์˜ ๊ฐ™์€ ์ด๋ฆ„์˜ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ์„œ, ๊ธฐ๋ณธ ํด๋ž˜์Šค์—์„œ ์„ ์–ธ๋œ ํ•จ์ˆ˜์™€ ๊ฐ™์€ ์ด๋ฆ„์˜ ํ•จ์ˆ˜๊ฐ€ ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜๋˜์–ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋˜์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค.

์ƒ์† ๊ณ„์ธต ๊ตฌ์กฐ์—์„œ์˜ ๋‹คํ˜•์„ฑ (polymorphism)

๋™์  ๋ฐ”์ธ๋”ฉ Dynamic binding =Late binding =Runtime binding

new ์—ฐ์‚ฐ์ž๋Š” ๋™์ ์œผ๋กœ ๋ฐฐ์—ด์„ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค.

2. Polymorphism ์‚ฌ๋ก€

์‚ฌ๋ก€: Animal ํด๋ž˜์Šค ๊ณ„์ธต์—์„œ ๋‹คํ˜•์„ฑ ๋™์ž‘

ํ•ธ๋“ค์ด๋ž€?

Polymorphism ๋™์ž‘ ๋ฉ”์ปค๋‹ˆ์ฆ˜

  1. Derived class ๊ฐ์ฒด๋ฅผ base class์˜ ํฌ์ธํ„ฐ/์ฐธ์กฐํ˜• ํ•ธ๋“ค๋กœ ๋ฐ›์Œ
  2. Base class์—์„œ ๊ฐ€์ƒ(virtual) ํ•จ์ˆ˜๋กœ ์„ ์–ธ๋œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ๋•Œ ๋™์ž‘

3. ํ•ธ๋“ค์˜ ์ž๋ฃŒํ˜•์— ์˜ํ•œ ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ํ˜ธ์ถœ (without Polymorphism)

Virtual ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๋•Œ (without using polymorphism)

๊ฐ€์ƒ ํ•จ์ˆ˜ (virtual function)์˜ ๊ธฐ๋Šฅ

ํ•ธ๋“ค์˜ ์ž๋ฃŒํ˜•์— ์˜ํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์˜ˆ์ œ (w/o polymorphism)

CommissionEmployee.h

#ifndef COMMISSIONEMPLOYEE_H
#define COMMISSIONEMPLOYEE_H

#include <string>
using namespace std;

class CommissionEmployee
{
public:
    CommissionEmployee(const string &, const string &, const string &,
                       double = 0.0, double = 0.0);

    void setFirstName(const string &);
    string getFirstName() const;

    void setLastName(const string &);
    string getLastName() const;

    void setSocialSecurityNumber(const string &);
    string getSocialSecurityNumber() const;

    void setGrossSales(double);
    double getGrossSales() const;

    void setCommissionRate(double);
    double getCommissionRate() const;

    double earnings() const;
    void print() const;

private:
    string firstName;
    string lastName;
    string socialSecurityNumber;
    double grossSales;
    double commissionRate;
};

#endif

CommissionEmployee.cpp

#include "CommissionEmployee.h"
#include <iostream>
#include <string>

using namespace std;

CommissionEmployee::CommissionEmployee(const string &first, const string &last, const string &ssn, double sales, double rate)
{
    firstName = first;
    lastName = last;
    socialSecurityNumber = ssn;
    setGrossSales(sales);
    setCommissionRate(rate);
}

double CommissionEmployee::earnings() const
{
    return commissionRate * grossSales;
}

double CommissionEmployee::getCommissionRate() const
{
    return commissionRate;
}

string CommissionEmployee::getFirstName() const
{
    return firstName;
}

double CommissionEmployee::getGrossSales() const
{
    return grossSales;
}

string CommissionEmployee::getLastName() const
{
    return lastName;
}

string CommissionEmployee::getSocialSecurityNumber() const
{
    return socialSecurityNumber;
}

void CommissionEmployee::print() const
{
    cout << "commission employee: "
         << getFirstName() << ' ' << getLastName() << endl
         << "social security number: " << getSocialSecurityNumber() << endl
         << "gross sales: " << getGrossSales() << endl
         << "commission rate: " << getCommissionRate() << endl;
}

void CommissionEmployee::setCommissionRate(double rate)
{
    commissionRate = (rate > 0.0 && rate < 1.0) ? rate : 0;
}

void CommissionEmployee::setFirstName(const string &first)
{
    firstName = first;
}

void CommissionEmployee::setGrossSales(double sales)
{
    grossSales = sales < 0.0 ? 0 : sales;
}

void CommissionEmployee::setLastName(const string &last)
{
    lastName = last;
}

void CommissionEmployee::setSocialSecurityNumber(const string &ssn)
{
    socialSecurityNumber = ssn;
}

BasePlusCommissionEmployee.h

#ifndef BASEPLUSCOMMISSIONEMPLOYEE_H
#define BASEPLUSCOMMISSIONEMPLOYEE_H

#include <string>
#include "CommissionEmployee.h"

using namespace std;

class BasePlusCommissionEmployee : public CommissionEmployee
{
private:
    double baseSalary;

public:
    BasePlusCommissionEmployee(const string &, const string &, const string &,
                               double = 0.0, double = 0.0, double = 0.0);

    void setBaseSalary(double);
    double getBaseSalary() const;

    void print() const;
    double earnings() const;
};

#endif

BasePlusCommissionEmployee.cpp

#include "BasePlusCommissionEmployee.h"
#include <iostream>
#include <string>
#include "CommissionEmployee.h"

using namespace std;

BasePlusCommissionEmployee::BasePlusCommissionEmployee(const string &first, const string &last, const string &ssn, double sales, double rate, double salary)
    : CommissionEmployee(first, last, ssn, sales, rate)
{
    setBaseSalary(salary);
}

double BasePlusCommissionEmployee::earnings() const
{
    return getBaseSalary() + CommissionEmployee::earnings();
}

double BasePlusCommissionEmployee::getBaseSalary() const
{
    return baseSalary;
}

void BasePlusCommissionEmployee::print() const
{
    cout << "base-salaried ";
    CommissionEmployee::print();
    cout << "base salary: " << baseSalary << endl;
}

void BasePlusCommissionEmployee::setBaseSalary(double salary)
{
    baseSalary = salary < 0.0 ? 0 : salary;
}

main.cpp

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-12-07 แ„‹แ…ฉแ„’แ…ฎ 10 36 17

print() ํ•จ์ˆ˜๋ฅผ virtual๋กœ ์„ ์–ธํ–ˆ์„ ๋•Œ์™€ ์•„๋‹ ๋•Œ์˜ ์ฐจ์ด์ (์œ„์—์„œ * ๋ถ€๋ถ„)์„ ํ™•์ธํ•  ๊ฒƒ

ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ํฌ์ธํ„ฐ๊ฐ€ ๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ๋•Œ

์˜ˆ์ œ (ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ํฌ์ธํ„ฐ๊ฐ€ ๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ๋•Œ)

main.cpp
#include "CommissionEmployee.h"
#include "BasePlusCommissionEmployee.h"

int main()
{
    CommissionEmployee commissionEmployee(
        "Sue", "Jones", "222-22-2222", 10000, .06);
    BasePlusCommissionEmployee *basePlusCommissionEmployeePtr = 0;

    // aim derived-class pointer at base-class object
    // Error: a CommissionEmployee is not a BasePlusCommissionEmployee
    basePlusCommissionEmployeePtr = &commissionEmployee;

    return 0;
}
Error Message

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-12-07 แ„‹แ…ฉแ„’แ…ฎ 10 44 04

๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ ํฌ์ธํ„ฐ๊ฐ€ ํŒŒ์ƒํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ๋•Œ

4. Polymorphism ๊ตฌํ˜„ (๊ฐ€์ƒ ํ•จ์ˆ˜์— ์˜ํ•œ ๋™์  ๋ฐ”์ธ๋”ฉ)

๊ฐ€์ƒ ํ•จ์ˆ˜ (Virtual Function) ์‚ฌ์šฉ์— ์˜ํ•œ ๋™์  ๋ฐ”์ธ๋”ฉ

๊ฐ€์ƒ ํ•จ์ˆ˜ (Virtual Function) ์„ ์–ธ

์ •์  ๋ฐ”์ธ๋”ฉ๊ณผ ๋™์  ๋ฐ”์ธ๋”ฉ

์ •์  ๋ฐ”์ธ๋”ฉ (static binding)

ํŠน์ • ๊ฐ์ฒด๊ฐ€ dot operator๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, virtual ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ํ˜ธ์ถœ๋œ ํ•จ์ˆ˜๋Š” (ํ•ธ๋“ค์— ์˜ํ•ด) ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๊ฒฐ์ •๋œ๋‹ค.

๋™์  ๋ฐ”์ธ๋”ฉ (dynamic binding)

๊ฐ€์ƒํ•จ์ˆ˜์˜ ๋™์  ๋ฐ”์ธ๋”ฉ์€ ํฌ์ธํ„ฐ ๋˜๋Š” ์ฐธ์กฐํ˜•์˜ ํ•ธ๋“ค์—์„œ๋งŒ ์ด๋ฃจ์–ด์ง„๋‹ค.

๋™์  ๋ฐ”์ธ๋”ฉ ์˜ˆ์ œ

CommissionEmployee.h

#ifndef COMMISSION_EMPLOYEE_H
#define COMMISSION_EMPLOYEE_H

#include <string>

using namespace std;

class CommissionEmployee
{
public:
    CommissionEmployee(const string &, const string &, const string &,
                       double = 0.0, double = 0.0);

    void setFirstName(const string &);
    string getFirstName() const;

    void setLastName(const string &);
    string getLastName() const;

    void setSocialSecurityNumber(const string &);
    string getSocialSecurityNumber() const;

    void setGrossSales(double);
    double getGrossSales() const;

    void setCommissionRate(double);
    double getCommissionRate() const;

    virtual double earnings() const;
    virtual void print() const;

private:
    // protected:
    string firstName;
    string lastName;
    string socialSecurityNumber;
    double grossSales;
    double commissionRate;
};

#endif

CommissionEmployee.h

#include <iostream>
using std::cout;

#include "CommissionEmployee.h"

CommissionEmployee::CommissionEmployee(
    const string &first, const string &last, const string &ssn,
    double sales, double rate)
{
    firstName = first;
    lastName = last;
    socialSecurityNumber = ssn;
    setGrossSales(sales);
    setCommissionRate(rate);
}

void CommissionEmployee::setFirstName(const string &first)
{
    firstName = first;
}

string CommissionEmployee::getFirstName() const
{
    return firstName;
}

void CommissionEmployee::setLastName(const string &last)
{
    lastName = last;
}

string CommissionEmployee::getLastName() const
{
    return lastName;
}

void CommissionEmployee::setSocialSecurityNumber(const string &ssn)
{
    socialSecurityNumber = ssn;
}

string CommissionEmployee::getSocialSecurityNumber() const
{
    return socialSecurityNumber;
}

void CommissionEmployee::setGrossSales(double sales)
{
    grossSales = (sales < 0.0) ? 0.0 : sales;
}

double CommissionEmployee::getGrossSales() const
{
    return grossSales;
}

void CommissionEmployee::setCommissionRate(double rate)
{
    commissionRate = (rate > 0.0 && rate < 1.0) ? rate : 0.0;
}

double CommissionEmployee::getCommissionRate() const
{
    return commissionRate;
}

double CommissionEmployee::earnings() const
{
    return commissionRate * grossSales;
}

void CommissionEmployee::print() const
{
    cout << "commission employee: " << firstName << ' ' << lastName
         << "\nsocial security number: " << socialSecurityNumber
         << "\ngross sales: " << grossSales
         << "\ncommission rate: " << commissionRate;
}

BasePlusCommissionEmployee.h

#ifndef BASE_PLUS_COMMISSION_EMPLOYEE_H
#define BASE_PLUS_COMMISSION_EMPLOYEE_H

#include <string>
#include "CommissionEmployee.h"

using namespace std;

class BasePlusCommissionEmployee : public CommissionEmployee
{
public:
    BasePlusCommissionEmployee(const string &, const string &, const string &,
                               double = 0.0, double = 0.0, double = 0.0);

    void setBaseSalary(double);
    double getBaseSalary() const;

    virtual double earnings() const;
    virtual void print() const;

private:
    double baseSalary;
};

#endif

BasePlusCommissionEmployee.cpp

#include <iostream>
using std::cout;

#include "BasePlusCommissionEmployee.h"

BasePlusCommissionEmployee::BasePlusCommissionEmployee(
    const string &first, const string &last, const string &ssn,
    double sales, double rate, double salary)
    : CommissionEmployee(first, last, ssn, sales, rate)
{
    setBaseSalary(salary);
}

void BasePlusCommissionEmployee::setBaseSalary(double salary)
{
    baseSalary = (salary < 0.0) ? 0.0 : salary;
}

double BasePlusCommissionEmployee::getBaseSalary() const
{
    return baseSalary;
}

double BasePlusCommissionEmployee::earnings() const
{
    // double tempCommissionRate = getCommissionRate();
    // double tempGrossSales = getGrossSales();
    // return baseSalary + (tempCommissionRate * tempGrossSales);
    return baseSalary + (getCommissionRate() * getGrossSales());
}

void BasePlusCommissionEmployee::print() const
{

    cout << "base-salaried commission emplyee: " << getFirstName() << ' '
         << getLastName() << "\nsocial security number: " << getSocialSecurityNumber()
         << "\ngross sales: " << getGrossSales()
         << "\ncommission rate: " << getCommissionRate()
         << "\nbase salary: " << baseSalary;
}

driver

#include <iostream>
#include <iomanip>

#include "BasePlusCommissionEmployee.h"
#include "CommissionEmployee.h"

using namespace std;

int main()
{
    CommissionEmployee commissionEmployee(
        "Sue", "Jones", "222-22-2222", 10000, 0.6);

    CommissionEmployee *commissionEmployeePtr = 0;

    BasePlusCommissionEmployee basePlusCommissionEmployee(
        "Bob", "Lewis", "333-33-3333", 5000, 0.04, 300);

    BasePlusCommissionEmployee *basePlusCommissionEmployeePtr = 0;

    cout << fixed << setprecision(2);

    cout << "Invoking print function on base-class and derived-class "
         << "\nobjects with static binding\n\n";
    commissionEmployee.print();
    cout << "\n\n";
    basePlusCommissionEmployee.print();

    cout << "\n\n\nInvoking print function on base-class and "
         << "derived-class \nobjects with dynamic binding:";

    commissionEmployeePtr = &commissionEmployee;
    cout << "\n\nCalling virtual function print with base-class pointer"
         << "\n to base-class object invokes base-class "
         << "print function:\n\n";
    commissionEmployeePtr->print();

    basePlusCommissionEmployeePtr = &basePlusCommissionEmployee;
    cout << "\n\nCalling virtual function print with derived-class "
         << "pointer\nto derived-class object invokes derived-class "
         << "print function:\n\n";
    basePlusCommissionEmployeePtr->print();

    commissionEmployeePtr = &basePlusCommissionEmployee;
    cout << "\n\nCalling virtual function print with base-class pointer "
         << "\nto derived-class object invokes derived-class "
         << "print function:\n\n";

    commissionEmployeePtr->print();
    cout << endl;
    return 0;
}

์‹คํ–‰ ๊ฒฐ๊ณผ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-12-07 แ„‹แ…ฉแ„’แ…ฎ 10 51 54

5. Abstract Classes and Pure Virtual Functions

์ถ”์ƒ ํด๋ž˜์Šค (Abstract Class)

์ˆœ์ˆ˜ virtual ํ•จ์ˆ˜ (Pure Virtual Function)

์ถ”์ƒ ๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ ๋‹คํ˜•์„ฑ์—์˜ ์ด์šฉ

๊ธฐ์กด Employee ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐœ์„ 

๊ธฐ์กด Employee ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐœ์„ 

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-12-07 แ„‹แ…ฉแ„’แ…ฎ 10 56 17

6. Case Study: Payroll System Using Polymorphism