과제1.
객체의 생성과 저장
- 기초 클래스와 파생클래스의 사이즈를 결정하는 요인
> 각 클래스의 사이즈를 결정하는 요인은 자료형임
> 선언되지 않은 자료형은 설사 기초 클래스의 자료형이더라도 크기의 영향을 주지 않는다.
> 함수는 사이즈의 영향을 주지 않는다
- 기초 클래스의 맴버 변수 주소값(위치)과, 파생클래스 맴버 변수의 주소값(위치)
#include<iostream>
using namespace std;
class Base{
public:
int data;
};
class Derived : public Base {
public:
double value;
};
int main(void){
Base b;
Derived d;
cout << "기초 클래스의 크기 : " << sizeof(b) << endl;
cout << "파생 클래스의 크기 : " << sizeof(d) << endl;
cout << "d의 주소 : " << &d << endl;
cout << "b의 주소 : " << &b << endl;
cout << "b의 int data의 주소 : " << &b.data << endl;
cout << "d의 int data의 주소 : " << &d.data << endl;
cout << "d의 double value의 주소 : " << &d.value << endl;
}

> 클래스 안 첫번째 멤버변수의 주소와 해당 객체의 주소의 시작은 같다
참고) 멤버변수가 int, double 형태로 되어 있는데 가장 큰 double의 8의 배수 형태로 정렬을 시도
따라서 d의 int data의 크기인 4byte 다음 비어있는 4byte 크기는 패딩(padding) 형태로 채운 것이고 8바이트로 정렬을 시도한 것으로 볼 수 있음
p.326~327
"기초클래스가 파생클래스의 객체를 가르킬 수 있다."의 의미를 문법적으로 설명하시오
#include<iostream>
using namespace std;
class Base{
private:
int data;
public:
Base() : data(0) {}
void BaseFunc(){
cout << "BaseFunc called" << endl;
}
void ShowAddress() const {
cout << "Base data address: " << &data << endl;
}
};
class Derived : public Base {
private:
double value;
public:
Derived() : value(0.0) {}
void DerivedFunc(){
cout << "DerivedFunc called" << endl;
}
void ShowAddress() const {
cout << "Derived value address: " << &value << endl;
}
};
int main(void){
Base* b = new Derived(); // 기초 클래스 포인터가 파생 클래스 객체를 가리킴
delete b;
return 0;
}
> main의 Base* b = new Derived()를 보면 Base(기초 클래스) 포인터로 Derived 객체를 가르키고 있는 것을 확인할 수 있다.
p.329
해당 페이지의 상속관계를 기반으로 "객체지향"이라는 용어를 사용하는 이유, 또는 OOP의 기술의 설계 목표가 무엇일지 "객체"를 기준으로 설명하시오
>
기초가 되는 객체를 기준으로 여러 객체들이 상속받는 형태로 확장이 가능하고, 이는 객체간의 계층이 나눠져있음을 의미함.
이처럼 객체들 관계를 중심으로 설계를 해나가기 때문에 "객체지향" 이라는 용어를 사용하는 것
p.331~332
- 클래스간의 상속 구조와, 47번 라인의 다형성이 사용되는 구조를 설명하시오
> Employee 기초 클래스를 기준으로 PermanentWorker 유도 클래스가 있는 상속구조이다
> AddEmployee 함수는 Employee 기초클래스를 인자로 받는데, 80~82줄의 main 내용을 보면 Permanent 유도클래스를 인자로 사용하고 있음을 알 수 있다. 이는 하나의 타입을 통해 다양한 객체를 동일한 방식으로 다룰 수 있는 '다형성' 을 의미한다.
- '오버라이딩'을 설명하시오
> 오버라이딩이란 기초 클래스의 선언된 함수와 동일한 이름과 형태로 유도 클래스에서 똑같이 선언하게 되면 해당 함수가 유도 클래스의 내용으로 덮히는 것을 말한다
p.335
[교재 지문] 그리고 이렇게 함수가 오버라이딩 되면, 오버라이딩 된 기초 클래스의 함수는, 오버라이딩을 한 유도 클래스의 함수에 가려진다. 그래서 위의 SalesWorker 클래스 내에서 Get Pay 함수를 호출하면 , SalesWorker 클래스에 정의된 GetPay 함수가 호출된다.
- 간단한 클래스 다이어그램을 기반으로, 문장을 설명하시오

> 위 다이어그램에서 SalesWorker의 GetPay 함수는 PermanentWorker의 GetPay 함수와 이름, 형태가 같아 오버라이딩 되므로 SaleWorker에서 GetPay 함수를 호출하게 되면 SaleWorker에 정의된 GetPay 함수가 호출됨.
- 오버라이딩과 오버로딩의 차이점을 설명하시오
> 오버라이딩은 상속관계에서 유도 클래스의 함수명과 형태가 기초 클래스와 같을 때 덮어지는 경우를 의미하고, 오버리딩은 함수명이 같지만 반환형이나 매개변수 차이에 따라 함수를 다르게 인식하는 것을 의미한다
p.339
[교재 지문]PermanentWorker 클래스의 ShowSalaryInfo 함수는 상속에 의해서 SalesWorker 객체에도 존재한다. 그러나 비록 상속이 되었다고는 하나 PermanentWorker 클래스의 ShowSalaryInfo 함수 내에서 호출되는 Get Pay 함수는 PermanentWorker 클래스에 정의된 Get Pay 함수의 호출로 이어지고 만다. 따라서 SalesWorker 클래스에 정의된 Get Pay 함수가 호출되도록 SalesWorker 클래스에 별도의 ShowSalaryInfo 함수를 삽입해야만 한다. 비록 함수의 몸체부분이 동일하더라도 말이다. 그래서 SalesWorker 클래스에서 ShowSalaryInfo 함수를 별도로 정의하고 있는 것이다.
- 간단한 클래스 다이어그램을 기반으로, 문장을 설명하시오

> 만약 SaleWorker에서 GetPay, ShowSalaryInfo 함수를 별도로 정의되지 않으면 SaleWorker에서 호출하는 GetPay, ShowSalary 함수는 PermanentWokrer에 정의된 기준으로 호출이 된다.
> SaleWorker에 별도로 두 함수를 정의하여 오버라이딩을 하면 SaleWorker 내의 호출은 SaleWorker에 오버라이딩된 함수를 기준으로 호출이 된다.
과제2.
p.341~342
- 교재의 예제 주석부분 //"컴파일 error!" 가 발생하는 3가지 경우에 대해 설명하시오
> Base(기초 클래스) 포인터에 Derived(파생 클래스) 객체를 저장하고 있는데, C++ 컴파일러는 포인터의 자료형으로 포인터 연산을 하기 때문에 기초 클래스형 포인터인 bptr이 가르키는 객체에 DerivedFunc 함수가 있다는 것을 알 수 없어 컴파일 에러가 발생한다.
> 기초 클래스형 포인터인 bptr을 유도 클래스형 포인터에 저장하는 경우인데, C++ 컴파일러는 유도 클래스형 포인터 dptr에 기초 클래스형 객체가 들어가는 것을 방지하기 위해 컴파일 에러를 발생시킨다.
p.342
[교재 지문] 포인터의 자료형을 기준으로 판단하지, 실제 가리키는 객체의 자료형을 기준으로 판단하지 않는다.
위 문장을 설명하시오
> Base *bptr = new Derived(); 의 경우 Base형 포인터를 기준으로 판단한다는 의미이다.
p.344~346
- 페이지 344 상단의 O, X 경우의 수에 대해 "포인터 형에 해당하는 클래스에 정의된 멤버에만 접근이 가능"한 이유를
논리적으로 설명하시오
> 컴파일러는 포인터를 이용한 연산을 판단할 때 포인터 자료형을 기준으로 판단하기 때문이다.
p.345
[교재 지문]"First형 포인터 변수를 이용하면 First 클래스에 정의된 MyFunc 함수가 호출되고, Second형 포인터 변수를 이용하면 Second 클래스에 정의된 MyFunc 함수가 호출되고, Third 형 포인터 변수를 이용하면 Third 클래스에 정의된 MyFunc 함수가 호출되는구나!"
- 간단한 클래스 다이어그램을 기반으로, 문장을 설명하시오

> 유도 클래스들의 함수들이 모두 기초 클래스의 함수의 이름과 형태를 가지고 있으므로 오버라이딩이 된 상태이다
> 포인터형을 기준으로 포인터 연산을 하기 때문에 각각의 포인터에 맞는 클래스의 오버라이딩 된 함수들이 사용됨
p.346~355 가상함수
- p.346 ‘‘함수를 오버라이딩을 했다는 것은, 해당 객체에서 호출되어야 하는 함수를 바꾼다는 의미인데, 포인터 변수의 자료형에 따라서 호출되는 함수의 종류가 달라지는 것은 문제가 있어 보입니다.” 를 설명하시오.
> 함수 오버라이딩의 의도는 기초 클래스가 아닌 유도 클래스 객체의 함수로 호출하기 위함인데 만약 기초 클래스 포인터 변수로 선언하게 되면 기초 클래스의 함수가 호출되므로 본래의 의도와 달라지게 된다.
- p.348 [교재 지문] 위의 실행결과에서 보이듯이 , "함수가 가상함수로 선언되면, 해당 함수호출 시, 포인터의 자료형을 기반으로 호출대상을 결정하지 않고, 포인터 변수가 실제로 가리키는 객체를 참조하여 호출의 대상을 결정한다" 를 비교 설명하시오.
> 함수가 일반함수로 선언되었을 때에는 포인터 자료형을 기반으로 호출대상을 결정하는 반면, 가상함수(vitual)로 선언하게 되면 포인터 변수가 가리키는 실제 객체를 호출대상으로 결정한다.
p.349~351
‘오렌지미디어 급여관리 확장성 문제’의 완전한 해결 구조 설명
> 기존의 주석되어 있던 부분이 컴파일 에러가 발생했던 이유는 Employee 클래스에 GetPay, ShowSalaryInfo 함수가 없음에도 불구하고 Employee형 포인터를 기준으로 연산을 처리했기 때문임.
> Employee 클래스에 GetPay, ShowSalaryInfo 함수를 새로 만들어 virtual(가상) 선언을 함으로써 유도 클래스들이 가상함수를 오버라이딩할 수 있도록 하여 실제 객체를 기준으로 연산을 처리하도록 해결함.
p.352
"공통적인 규약"의 의미 설명
> 공통적인 규약은 기초가 되는 객체가 정의한 규칙을 상속 및 확장되는 클래스들이 모두 적용받을 수 있도록 하겠다는 의미임.
p.356
"다형성"의 의미 설명
> 다형성이란 하나의 인터페이스가 여러 특성을 가질 수 있는 능력을 의미함.
> 여기서 First 포인터인 ptr이라는 변수는 어떤 객체를 참조하느냐에 따라 First가 될 수도 있고, 이를 상속받은 Second가 될 수도 있다.
'LMS 7 > 개발일지' 카테고리의 다른 글
| 25.08.06 학습개발일지 / QT6 Chapter 05(1) (2) | 2025.08.10 |
|---|---|
| 25.08.04 학습개발일지 / C++ Study6(2) (4) | 2025.08.04 |
| 25.08.01 학습개발일지 C++ Study5 (2) | 2025.08.01 |
| 25.07.31 학습개발일지 C++ Study5 (11) | 2025.07.31 |
| 25.07.30 개발학습일지 / C++ Study4(chapter 5, chapter 6) (2) | 2025.07.30 |