과제3.
p.376
챕터 목표: *멤버함수가 실제로 어디에 존재하는지를 설명
> 멤버함수는 메모리 중 별도의 공간에 존재하고, 해당 클래스를 참조하는 객체가 이 함수를 공유하는 형태임
p.377~382
가상함수의 동작 원리를
1) 메모리 관점에서
2) 객체 사이즈와
3) 가상함수 테이블과
4) 런타임용어를 사용해 설명할 것
#include <iostream>
using namespace std;
class A {
int x;
};
class B {
int x;
void func() {}
};
int main() {
cout << "sizeof(A): " << sizeof(A) << endl;
cout << "sizeof(B): " << sizeof(B) << endl;
}

#include <iostream>
using namespace std;
class A {
int x;
};
class B {
int x;
virtual void func() {}
};
int main() {
cout << "sizeof(A): " << sizeof(A) << endl;
cout << "sizeof(B): " << sizeof(B) << endl;
}

> 가상함수는 컴파일시 메모리 중 별도의 공간에 가상함수 테이블을 생성하여, 실제 객체 생성과 상관없이 메모리 공간에 할당된다. 하지만 이 경우 생성된 객체 내부에는 가상함수 테이블에 대한 포인터가 자동으로 포함되기 때문에 객체 사이즈에 영향을 준다. 가상함수 테이블 포인터는 64비트 체제에서 8byte의 크기를 가지고 있음.
p.390
프로젝트 07단계
<Account.h>
//Account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
class Account
{
private:
int accID;
int balance;
char * cusName;
public:
Account(int ID, int money, char * name);
Account(const Account & ref);
int GetAccID() const;
virtual void Deposit(int money);
int Withdraw(int money) ;
void ShowAccInfo() const ;
~Account();
};
#endif
<Account.cpp>
// Account.cpp
#include "BankingCommonDecl.h"
#include "Account.h"
Account::Account(int ID, int money, char * name)
: accID(ID), balance(money)
{
cusName=new char[strlen(name)+1];
strcpy(cusName, name);
}
Account::Account(const Account & ref)
: accID(ref.accID), balance(ref.balance)
{
cusName=new char[strlen(ref.cusName)+1];
strcpy(cusName, ref.cusName);
}
int Account::GetAccID() const { return accID; }
void Account::Deposit(int money)
{
balance+=money;
}
int Account::Withdraw(int money)
{
if(balance<money)
return 0;
balance-=money;
return money;
}
void Account::ShowAccInfo() const
{
cout<<"계좌ID: "<<accID<<endl;
cout<<"이 름: "<<cusName<<endl;
cout<<"잔 액: "<<balance<<endl;
}
Account::~Account()
{
delete []cusName;
}
> Account와 이를 상속받은 클래스들은 사전에 선언되어 있는 데이터들을 관리하기 위한 데이터 클래스이다.
> Account(기초 클래스)에 대한 선언(.h)과 정의(.cpp)에 대한 파일임
> Deposit 멤버함수는 실제 객체를 생성할 때 유도 클래스를 기준으로 함수를 호출하기 위해 가상함수(virtual)가 사용됨
<NormalAccount.h>
// NormalAccount.h
#ifndef __NORMAL_ACCOUNT_H__
#define __NORMAL_ACCOUNT_H__
#include "Account.h"
class NormalAccount : public Account
{
private:
int interRate; // 이자율 %단위
public:
NormalAccount(int ID, int money, char * name, int rate)
: Account(ID, money, name), interRate(rate)
{ }
virtual void Deposit(int money)
{
Account::Deposit(money); // 원금추가
Account::Deposit(money*(interRate/100.0)); // 이자추가
}
};
#endif
> Account 클래스의 상속을 받은 NormalAccount 클래스임
> 기초 클래스의 virtual 선언으로 유도 클래스의 virtual 선언은 필요하지 않지만 가독성을 위해서는 붙여주는 것을 권장하고 있음
<HighCreditAccount.h>
// HighCreditAccount.h
#ifndef __HIGHCREDIT_ACCOUNT_H__
#define __HIGHCREDIT_ACCOUNT_H__
#include "NormalAccount.h"
class HighCreditAccount : public NormalAccount
{
private:
int specialRate;
public:
HighCreditAccount(int ID, int money, char * name, int rate, int special)
: NormalAccount(ID, money, name, rate), specialRate(special)
{ }
virtual void Deposit(int money)
{
NormalAccount::Deposit(money); // 원금과 이자추가
Account::Deposit(money*(specialRate/100.0)); // 특별이자추가
}
};
#endif
> NormalAccount 클래스의 상속을 받은 HighCreditAccount 클래스임
> virtual 선언은 위와 같은 이유로 되었음
<AccountHandler.h>
// AccountHandler.h
#ifndef __ACCOUN_HANDLER_H__
#define __ACCOUN_HANDLER_H__
#include "Account.h"
class AccountHandler
{
private:
Account * accArr[100];
int accNum;
public:
AccountHandler();
void ShowMenu(void) const;
void MakeAccount(void);
void DepositMoney(void);
void WithdrawMoney(void);
void ShowAllAccInfo(void) const;
~AccountHandler();
protected:
void MakeNormalAccount(void);
void MakeCreditAccount(void);
};
#endif
<AccountHandler.cpp>
// AccountHandler.cpp
#include "BankingCommonDecl.h"
#include "AccountHandler.h"
#include "Account.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"
void AccountHandler::ShowMenu(void) const
{
cout<<"-----Menu------"<<endl;
cout<<"1. 계좌개설"<<endl;
cout<<"2. 입 금"<<endl;
cout<<"3. 출 금"<<endl;
cout<<"4. 계좌정보 전체 출력"<<endl;
cout<<"5. 프로그램 종료"<<endl;
}
void AccountHandler::MakeAccount(void)
{
int sel;
cout<<"[계좌종류선택]"<<endl;
cout<<"1.보통예금계좌 ";
cout<<"2.신용신뢰계좌 "<<endl;
cout<<"선택: ";
cin>>sel;
if(sel==NORMAL)
MakeNormalAccount();
else
MakeCreditAccount();
}
void AccountHandler::MakeNormalAccount(void)
{
int id;
char name[NAME_LEN];
int balance;
int interRate;
cout<<"[보통예금계좌 개설]"<<endl;
cout<<"계좌ID: "; cin>>id;
cout<<"이 름: "; cin>>name;
cout<<"입금액: "; cin>>balance;
cout<<"이자율: "; cin>>interRate;
cout<<endl;
accArr[accNum++]=new NormalAccount(id, balance, name, interRate);
}
void AccountHandler::MakeCreditAccount(void)
{
int id;
char name[NAME_LEN];
int balance;
int interRate;
int creditLevel;
cout<<"[신용신뢰계좌 개설]"<<endl;
cout<<"계좌ID: "; cin>>id;
cout<<"이 름: "; cin>>name;
cout<<"입금액: "; cin>>balance;
cout<<"이자율: "; cin>>interRate;
cout<<"신용등급(1toA, 2toB, 3toC): "; cin>>creditLevel;
cout<<endl;
switch(creditLevel)
{
case 1:
accArr[accNum++]=new HighCreditAccount(id, balance, name, interRate, LEVEL_A);
break;
case 2:
accArr[accNum++]=new HighCreditAccount(id, balance, name, interRate, LEVEL_B);
break;
case 3:
accArr[accNum++]=new HighCreditAccount(id, balance, name, interRate, LEVEL_C);
}
}
void AccountHandler::DepositMoney(void)
{
int money;
int id;
cout<<"[입 금]"<<endl;
cout<<"계좌ID: "; cin>>id;
cout<<"입금액: "; cin>>money;
for(int i=0; i<accNum; i++)
{
if(accArr[i]->GetAccID()==id)
{
accArr[i]->Deposit(money);
cout<<"입금완료"<<endl<<endl;
return;
}
}
cout<<"유효하지 않은 ID 입니다."<<endl<<endl;
}
void AccountHandler::WithdrawMoney(void)
{
int money;
int id;
cout<<"[출 금]"<<endl;
cout<<"계좌ID: "; cin>>id;
cout<<"출금액: "; cin>>money;
for(int i=0; i<accNum; i++)
{
if(accArr[i]->GetAccID()==id)
{
if(accArr[i]->Withdraw(money)==0)
{
cout<<"잔액부족"<<endl<<endl;
return;
}
cout<<"출금완료"<<endl<<endl;
return;
}
}
cout<<"유효하지 않은 ID 입니다."<<endl<<endl;
}
AccountHandler::AccountHandler() : accNum(0)
{ }
void AccountHandler::ShowAllAccInfo(void) const
{
for(int i=0; i<accNum; i++)
{
accArr[i]->ShowAccInfo();
cout<<endl;
}
}
AccountHandler::~AccountHandler()
{
for(int i=0; i<accNum; i++)
delete accArr[i];
}
> AccountHandler은 데이터 클래스를 활용해서 실제 데이터들을 관리할 수 있는 기능을 가진 기능적 클래스임
> protected 선언이 된 멤버함수 MakeNormalAccount, MakeCreditAccount의 경우는 public 멤버함수인 MakeAccount로만 접근을 할 수 있도록 하는 의도를 가짐과 동시에 상속에 의한 확장성도 고려한 것으로 보임
<BankingCoomnDecl.h>
// BankingCommonDecl.h
#ifndef __BANKING_COMMON_H__
#define __BANKING_COMMON_H__
#include <iostream>
#include <cstring>
using namespace std;
const int NAME_LEN=20;
// 프로그램 사용자의 선택 메뉴
enum {MAKE=1, DEPOSIT, WITHDRAW, INQUIRE, EXIT};
// 신용등급
enum {LEVEL_A=7, LEVEL_B=4, LEVEL_C=2};
// 계좌의 종류
enum {NORMAL=1, CREDIT=2};
#endif
> C++ 표준 라이브러리와 열거형(enum)을 선언함
<BankingSystemMain.cpp>
// BankingSystemMain.cpp
#include "BankingCommonDecl.h"
#include "AccountHandler.h"
int main(void)
{
AccountHandler manager;
int choice;
while(1)
{
manager.ShowMenu();
cout<<"선택: ";
cin>>choice;
cout<<endl;
switch(choice)
{
case MAKE:
manager.MakeAccount();
break;
case DEPOSIT:
manager.DepositMoney();
break;
case WITHDRAW:
manager.WithdrawMoney();
break;
case INQUIRE:
manager.ShowAllAccInfo();
break;
case EXIT:
return 0;
default:
cout<<"Illegal selection.."<<endl;
}
}
return 0;
}
<Makefile>
CC = g++
CFLAGS = -Wall -g -I/usr/include/mysql
LDFLAGS = -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -Wl, -rpath,/usr/lib/x86_64-linux-gnu
SRCS = BankingSystemMain.cpp AccountHandler.cpp Account.cpp
OBJS = $(SRCS: .cpp= .o)
Target = myprogram
all: $(Target)
$(Target): $(OBJS)
$(CC) $(OBJS) -o $@
%.o: %.cpp
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(Target) *.o

'LMS 7 > 개발일지' 카테고리의 다른 글
| 25.08.07 학습개발일지 / QT6 Chapter05(2) (2) | 2025.08.11 |
|---|---|
| 25.08.06 학습개발일지 / QT6 Chapter 05(1) (2) | 2025.08.10 |
| 25.08.02 학습개발일지 / C++ Study 6(1) (0) | 2025.08.02 |
| 25.08.01 학습개발일지 C++ Study5 (2) | 2025.08.01 |
| 25.07.31 학습개발일지 C++ Study5 (11) | 2025.07.31 |