연습 문제
1번
Base 클래스와 Base 클래스를 상속받는 Derived1과 Derived2 클래스가 있다고 합시다. 이 클래스를 다형성 관계로 활용하려고 합니다. 각 클래스에 가상 print 함수와 가상 소멸자가 있는 경우의 가상 테이블을 그림으로 표현하세요.
2번
다음과 같은 두 클래스가 있다고 합시다. 두 클래스가 다형성을 갖게 스택 메모리 위에 인스턴스화하는 코드를 작성하세요. 다형성을 활용한다는 것은 부모 클래스에 대한 포인터를 사용한다는 것입니다. 다만 객체의 실체를 스택 메모리에 만들어서 활용하라는 것이 문제의 포인트입니다.
class First
{
private:
int fr;
public:
First(int fr);
virtual ~First();
virtual void print() const;
};
class Second : public First
{
private:
int se;
public:
Second(int fr, int se);
~Second();
void print() const;
};
풀이.
int main()
{
First* ptr;
First first(1);
Second second(1, 2);
//스택에 생성된 First 객체를 ptr로 가리킴
ptr = &First;
ptr->print();
//스택에 생성된 Second 객체를 ptr로 가리킴
ptr = &Second;
ptr->Second;
}
3번
2번을 변경해서, 객체를 힙 메모리 위에 만드세요.
풀이.
int main()
{
First* ptr;
ptr = new First(1);
ptr->print();
delete ptr;
ptr = new Secnod(1, 2);
ptr->print();
delete prt;
}
4번
상속 관계를 갖는 Base 클래스와 Derived 클래스가 있고, Base 클래스가 Base1 클래스라는 다른 클래스를 포함(composition)하고 있다고 할 때, 세 클래스의 UML 다이어그램을 그리세요.
풀이.
5번
다음과 같은 클래스가 있을 때, 가상 베이스 클래스 또는 믹스인 클래스가 필요한지 생각해보고, 왜 그런지 설명하세요.
풀이.
필요하지 않다.
가상 베이스 클래스, 믹스인 클래스는 다중 상속으로 인해 발생하는 문제를 해결하기 위해 사용한다.
두 개 이상의 베이스 클래스를 상속 받는 다중 상속 클래스가 없으므로 사용할 필요 없다.
6번
다음과 같은 코드가 있을 떄, 클래스 A와 B가 다형성을 활용하게 해서 적절한 print 함수를 호출하게 하려면, 무엇을 추가해야 할지 설명하세요.
class A { ... };
class B : public A { ... };
int main()
{
A* ptr;
ptr = new A();
ptr->print();
ptr = new B();
ptr->print();
return 0;
}
다형성을 구성하는 요소에는 포인터와 레퍼런스, 플러그 호환 객체, 가상 함수가 있다.
포인터 ptr이 있고, 객체도 존재하므로 나머지 요소인 가상 함수가 필요하다.
print 함수를 virtual 키워드를 통해 가상함수로 작성해야 한다.
7번
다음과 같은 클래스가 있을 떄, 다중 상속 문제가 어떤 클래스에서 발생하는지 찾고, 왜 발생하는지 설명하세요.
풀이.
클래스 ABC는 AA, AB, AC라는 세 개의 베이스 클래스를 가진다.
AA와 AB는 A라는 베이스 클래스를 가지므로 ABC는 A의 데이터 멤버를 중복 상속받게 되고,
AB와 BB는 B라는 베이스 클래스를 가지므로 ABC는 B의 데이터 멤버를 중복 상속받게 된다.
따라서 다중 상속 문제가 발생하게 된다.
프로그래밍 문제
1번
다음과 같은 다형성 관계를 갖는 클래스들이 있다고 합시다.
Employee 클래스는 first name, initial, last name을 데이터 멤버로 갖는 추상 클래스입니다. SalaryEmployee 클래스는 고정적인 월급을 받는 직원을 나타냅니다. HourlyEmployee 클래스는 고정된 시급을 월 단위로 받는 직원을 나타냅니다. 이러한 클래스들의 인터페이스 파일과 구현 파일을 작성하고, 이를 사용해보는 애플리케이션 프로그램도 만드세요.
employee.h
#pragma once
#include <string>
#include <iostream>
using namespace std;
class Employee
{
private:
string firstName;
string initial;
string lastName;
public:
Employee();
~Employee();
//세터 함수
void setFirstName(string fn);
void setInitial(string i);
void setLastName(string ln);
//게터 함수
string getFirstName();
string getInitial();
string getLastName();
//자식 클래스에서 꼭 정의해야 하는 가상 함수
virtual void print() = 0;
virtual double getSalary() = 0;
};
employee.cpp
#include "employee.h"
Employee::Employee()
:firstName("Hong"), initial("HGD"), lastName("GilDong")
{}
Employee::~Employee()
{}
void Employee::setFirstName(string fn)
{
this->firstName = fn;
}
void Employee::setInitial(string i)
{
this->initial = i;
}
void Employee::setLastName(string ln)
{
this->lastName = ln;
}
string Employee::getFirstName()
{
return firstName;
}
string Employee::getInitial()
{
return initial;
}
string Employee::getLastName()
{
return lastName;
}
hourlyEmployee.h
#pragma once
#include "employee.h"
class HourlyEmployee : public Employee
{
private:
int hourlySalary; //시급
public:
HourlyEmployee(int salary = 0);
~HourlyEmployee();
void print();
double getSalary();
};
hourlyEmployee.cpp
#include "hourlyEmployee.h"
HourlyEmployee::HourlyEmployee(int salary)
:hourlySalary(salary)
{}
HourlyEmployee::~HourlyEmployee()
{}
void HourlyEmployee::print()
{
cout << "이름: " << getFirstName() << " " << getLastName() << ", " << getInitial() << "\n";
cout << "월급: " << getSalary() << "\n";
}
double HourlyEmployee::getSalary()
{
return hourlySalary * 40 * 4; //시급 * 주 40시간 * 4주
}
salaryEmployee.h
#pragma once
#include "employee.h"
class SalaryEmployee : public Employee
{
private:
int monthlySalary; //월급
public:
SalaryEmployee(int salary = 0);
~SalaryEmployee();
void print();
double getSalary();
};
salaryEmployee.cpp
#include "salaryEmployee.h"
SalaryEmployee::SalaryEmployee(int salary)
:monthlySalary(salary)
{}
SalaryEmployee::~SalaryEmployee()
{}
void SalaryEmployee::print()
{
cout << "이름: " << getFirstName() << " " << getLastName() << ", " << getInitial() << "\n";
cout << "월급: " << getSalary() << "\n";
}
double SalaryEmployee::getSalary()
{
return monthlySalary; //월급
}
app.cpp
#include "hourlyEmployee.h"
#include "salaryEmployee.h"
int main(void)
{
SalaryEmployee A(3000000);
A.setInitial("KMS");
A.setFirstName("Kim");
A.setLastName("MinSu");
A.print();
HourlyEmployee B(25000);
B.setInitial("PJH");
B.setFirstName("Park");
B.setLastName("JinHong");
B.print();
}
2번
1번에 SalaryHourlyEmployee 클래스를 추가한다고 합시다. SalaryHourlyEmployee 클래스는 고정적인 월급도 받고, 180 시간이 넘는 업무 시간에 대해서 추가적으로 시급을 받는 직원을 나타냅니다. 다음과 같이 2개의 추상 클래스 SalaryType과 HourlyType 클래스를 추가해서 다중 상속을 피하고, 믹스인 클래스를 활용하는 형태로 코드를 구성하세요. 이러한 클래스들의 인터페이스 파일과 구현 파일을 작성하고, 이를 사용하는 애플리케이션 프로그램도 만드세요.
hourlyType.h
#pragma once
#include <iostream>
using namespace std;
class HourlyType
{
protected:
int hourlySalary; //시급
};
salaryType.h
#pragma once
#include <iostream>
using namespace std;
class SalarayType
{
protected:
int monthlySalary; //월급
};
employee.h
#pragma once
#include <string>
#include <iostream>
using namespace std;
class Employee
{
private:
string firstName;
string initial;
string lastName;
public:
Employee();
~Employee();
//세터 함수
void setFirstName(string fn);
void setInitial(string i);
void setLastName(string ln);
//게터 함수
string getFirstName();
string getInitial();
string getLastName();
//자식 클래스에서 꼭 정의해야 하는 가상 함수
virtual void print() = 0;
virtual double getSalary() = 0;
};
employee.cpp
#include "employee.h"
Employee::Employee()
:firstName("Hong"), initial("HGD"), lastName("GilDong")
{}
Employee::~Employee()
{}
void Employee::setFirstName(string fn)
{
this->firstName = fn;
}
void Employee::setInitial(string i)
{
this->initial = i;
}
void Employee::setLastName(string ln)
{
this->lastName = ln;
}
string Employee::getFirstName()
{
return firstName;
}
string Employee::getInitial()
{
return initial;
}
string Employee::getLastName()
{
return lastName;
}
hourlyEmployee.h
#pragma once
#include "hourlyType.h"
#include "employee.h"
class HourlyEmployee : public HourlyType, public Employee
{
public:
HourlyEmployee(int salary = 0);
void print();
double getSalary();
};
hourlyEmployee.cpp
#include "hourlyEmployee.h"
HourlyEmployee::HourlyEmployee(int salary)
{
hourlySalary = salary;
}
void HourlyEmployee::print()
{
cout << "이름: " << getFirstName() << " " << getLastName() << ", " << getInitial() << "\n";
cout << "월급: " << getSalary() << "\n";
}
double HourlyEmployee::getSalary()
{
return hourlySalary * 180; //월 180시간 근무로 계산
}
salaryEmployee.h
#pragma once
#include "salaryType.h"
#include "employee.h"
class SalaryEmployee :public Employee, public SalarayType
{
public:
SalaryEmployee(int salary = 0);
void print();
double getSalary();
};
salaryEmployee.cpp
#include "salaryEmployee.h"
SalaryEmployee::SalaryEmployee(int salary)
{
monthlySalary = salary;
}
void SalaryEmployee::print()
{
cout << "이름: " << getFirstName() << " " << getLastName() << ", " << getInitial() << "\n";
cout << "월급: " << getSalary() << "\n";
}
double SalaryEmployee::getSalary()
{
return monthlySalary; //월급
}
salaryHourlyEmployee.h
#pragma once
#include "hourlyType.h"
#include "salaryType.h"
#include "employee.h"
class SalaryHourlyEmployee :public HourlyType, public SalarayType, public Employee
{
private:
int workTime;
public:
SalaryHourlyEmployee(int mSalary, int hSalary,int workTIme);
void print();
double getSalary();
};
salaryHourlyEmployee.cpp
#include "salaryHourlyEmployee.h"
SalaryHourlyEmployee::SalaryHourlyEmployee(int mSalary, int hSalary, int workTime)
{
hourlySalary = hSalary;
monthlySalary = mSalary;
this->workTime = workTime;
}
void SalaryHourlyEmployee::print()
{
cout << "이름: " << getFirstName() << " " << getLastName() << ", " << getInitial() << "\n";
cout << "월급: " << getSalary() << "\n";
}
double SalaryHourlyEmployee::getSalary()
{
//180시간 이상 추가 근무 수당 계산
return monthlySalary + (workTime - 180) * hourlySalary;
}
app.cpp
#include "salaryHourlyEmployee.h"
#include "salaryEmployee.h"
#include "hourlyEmployee.h"
int main(void)
{
SalaryEmployee A(3000000);
A.setInitial("KMS");
A.setFirstName("Kim");
A.setLastName("MinSu");
A.print();
HourlyEmployee B(25000);
B.setInitial("PJH");
B.setFirstName("Park");
B.setLastName("JinHong");
B.print();
SalaryHourlyEmployee C(3000000, 25000, 190);
C.setInitial("JYH");
C.setFirstName("Jeong");
C.setLastName("Young Hyun");
C.print();
}
'프로그래밍 > C, C++' 카테고리의 다른 글
포르잔 C++ 바이블 Ch.11 연습문제 & 프로그래밍 문제 (1) | 2023.01.28 |
---|---|
[C++]vector를 2차원으로 선언하는 방법 (0) | 2022.12.27 |
[C++] 생성자와 소멸자 (0) | 2022.12.13 |
[C++] 클래스의 구조 (0) | 2022.12.11 |
while 반복문을 종료하는 방법: 센티넬, EOF, 플래그 (0) | 2022.12.10 |