본문 바로가기
프로그래밍/C++

C++ ] 클래스를 활용한 자판기 프로그램 + 함수 뒤에 붙는 const의 의미

by eteo 2022. 6. 16.


VendingMachine.h

#define DRINKNUM 4
#define MAXSTOCK 4

struct _DRINK {
	const char* name;
	int price;
	int stock;
};

class VendingMachine
{
private:
	_DRINK drink[DRINKNUM];
	int MyMoney;
	int MinPrice;

public:
	VendingMachine(const char* name1, int price1, const char* name2, int price2, const char* name3, int price3, const char* name4, int price4);
	void showList();
	void chkMinPrice();
	int GetMoney() const;
	bool SetMoney(int money);
	int takeMoney();
	bool sale();

};

 

클래스 VendingMachine 은 멤버변수로 구조체배열인 drink와 MyMoney, MinPrice를 가진다.

 

생성자에서 음료수 명은 수정하지 않는다는 가정하에 const char * 로 리터럴 문자열을 받는다.

 

일단 getter, setter는 GetMoney, SetMoney 함수만 만들어 뒀는데 나중에 추가할 예정이다.

 

 

main.h

#ifndef __MAIN_H__
#define __MAIN_H__

#include "VendingMachine.h"

enum class Status {
	SELECTMACHINE,
	MONEYINPUT,
	SALE,
};

bool SelectVender(VendingMachine& vender1, VendingMachine& vender2, VendingMachine& selected);

#endif

 

자판기 두 대중 한대를 선택하게끔하는 함수 SelectVender와 자판기의 상태를 표현하는 enum class Status를 두었다.

 

VendingMachine.cpp

#include "VendingMachine.h"
#include <iostream>
#include <windows.h>

using namespace std;

vendingMachine::vendingMachine(const char* name1, int price1, const char* name2, int price2, const char* name3, int price3, const char* name4, int price4)
	: MyMoney(0), MinPrice(9999)
{
	drink[0].name = name1;
	drink[0].price = price1;
	drink[1].name = name2;
	drink[1].price = price2;
	drink[2].name = name3;
	drink[2].price = price3;
	drink[3].name = name4;
	drink[3].price = price4;

	for (int i = 0; i < DRINKNUM; i++) {
		drink[i].stock = MAXSTOCK;
	}
}

void vendingMachine::showList(void) {
	cout << drink[0].name << " " << drink[0].price << "," << drink[1].name << " " << drink[1].price << ","
		<< drink[2].name << " " << drink[2].price << "," << drink[3].name << " " << drink[3].price << endl;
}


void vendingMachine::chkMinPrice(void) {
	int min = drink[0].price;
	for (int i = 0; i < DRINKNUM; i++) {
		min = (drink[i].price < min) ? drink[i].price : min;
	}
	MinPrice= min;
}

int vendingMachine::GetMoney() const {
	return MyMoney;
}
bool vendingMachine::SetMoney(int money) {
	if (money < 0 || money > 10000) {
		cout << "잘못된 금액을 투입하셨습니다." << endl;
		Sleep(500);
		return false;
	}
	MyMoney = money;
	return true;
}

int vendingMachine::takeMoney(void) {
	int money;
	system("cls");
	cout << "음료수 자판기==================================" << endl;
	cout << "돈을 투입해주세요: ";
	cin >> money;
	return money;
}

bool vendingMachine::sale() {

	// 잔액이 음료수 중 최저가보다 작은 경우 바로 반환
	if (MyMoney < MinPrice) {		
		cout << endl << "음료가 나옵니다." << endl;
		cout << "반환구에서 구입하신 음료와 거스름돈을 가져가세요." << endl;
		cout << "[ 거스름돈: " << MyMoney << "원 ]" << endl;
		system("pause");
		return 1;
	}
	
	system("cls");
	cout << "[ 현재금액: " << MyMoney << "원 ]" << endl;

	int select = 0;

	for (int i = 0; i < DRINKNUM; i++) {

		printf("%d. %-10s %15d\n", i + 1, drink[i].name, drink[i].price);

	}
	cout << "----------------------------------------------" << endl << endl;
	printf("구입할 음료수를 선택해주세요: _ (음료를 꺼내려면 -1을 선택해주세요)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
	cin >> select;

	// 사용자가 -1 선택한 경우 현재 잔액 반환
	if (select == -1) {
		cout << "반환구에서 구입하신 음료와 거스름돈을 가져가세요." << endl;
		cout << "[ 거스름돈: " << MyMoney << "원 ]" << endl << endl;
		system("pause");
		return 1;
	}

	if (select <= 0 || select > DRINKNUM) {
		cout << "잘못 입력하셨습니다." << endl;
		Sleep(500);
		return 0;
	}

	// 선택한 음료의 재고가 없거나 잔액이 부족한 경우가 아니라면 현재잔액에서 선택음료 가격 차감하고 재고 감소시킴
	if (MyMoney - drink[select - 1].price < 0) {
		cout << endl;
		cout << "잔액이 부족하여 해당제품은 구입할 수 없습니다. " << endl;
	}
	else if (drink[select - 1].stock <= 0) {
		cout << endl;
		cout << "재고가 부족하여 해당제품은 구입할 수 없습니다. " << endl;
	}
	else {
		MyMoney -= drink[select - 1].price;
		drink[select - 1].stock--;		
	}

	return 0;

}


생성자를 조금 정돈시켜서 다시 만들어보려고한다. 그리고 다음엔 거스름돈을 돌려주는 함수를 따로 뺄 생각중이다.

 

 

Main.cpp

#include <iostream>
#include "main.h"
#include "VendingMachine.h"
#include <windows.h>



using namespace std;

int main(void) {

	VendingMachine vender1("콜라",700,"사이다",800,"맥콜",900,"환타",1100);
	VendingMachine vender2("밀크티", 900, "우롱티", 600, "솔의눈", 1200, "우유", 800);

	VendingMachine& Selected = vender1;

	Status salestatus = Status::SELECTMACHINE; // enum class
	
	while (1) {
		if (salestatus == Status::SELECTMACHINE) {
			if (SelectVender(vender1, vender2, Selected)) {	// 자판기 1, 2 중 선택
				Selected.chkMinPrice();	// 최저가 확인
				salestatus = Status::MONEYINPUT;
			}		
		}
		else if (salestatus == Status::MONEYINPUT) {
			if (Selected.SetMoney(Selected.takeMoney())) {	// 돈 입력받음
				salestatus = Status::SALE;
			}
		}
		else if (salestatus == Status::SALE) {
			if (Selected.sale()) {							// 판매중
				salestatus = Status::SELECTMACHINE;
			}
		}
	}
	return 0;
}


bool SelectVender(VendingMachine& vender1, VendingMachine& vender2, VendingMachine& selected) {

	while (1) {
		int select;
		system("cls");
		cout << ">> 자판기를 선택해 주세요" << endl;
		cout << "자판기1 : ";
		vender1.showList();
		cout << "자판기2 : ";
		vender2.showList();
		cout << "[_]\b\b";
		cin >> select;
		if (select == 1) {
			selected = vender1;
			return true;
		}
		else if (select == 2) {
			selected = vender2;
			return true;
		}
		else {				
			cout << "다시 선택해 주세요." << endl;			
			Sleep(500);
			return false;
		}
	}
}

 

while문은 크게 SELECTMACHINE, MONEYINPUT, SALE 세가지 상태로 구분된다.

 

VendingMachine& Selected = vender1; 은 참조자는 선언과 동시에 초기화되어야 하기 때문에 임시로 vender1을 넣어준 것이고 아래 while문에서 어차피 사용자가 제대로 vender 선택을 했을 때만 다음 단계로 넘어가기 때문에 문제가 없다.

 

모든 재고가 0일경우 바로 반환하게끔 추가 예정.

 

 

 

 

함수 뒤에 붙는 const의 의미

 

C++에서 함수 뒤에 const가 붙는 것은 해당 함수가 멤버 함수일 때만 의미가 있다. 멤버 함수 뒤에 const가 붙으면 그 멤버함수가 객체의 멤버 변수를 수정하지 않는다는 것을 의미한다.

만약 뒤에 const가 붙은 멤버 함수 내에서 멤버 변수를 변경하려고 하면 컴파일 오류가 발생한다. 또한 const가 붙은 멤버 함수는 역시 const가 붙어있는 함수만을 내부에서 호출할 수 있다.

 

예를 들어 다음과 같은 코드가 있다고 가정해보자.

class MyClass {
public:
    int getValue() const { 
        return value; 
    }
    
    void setValue(int v) { 
        value = v; 
    }

private:
    int value;
};

 

위의 getValue() 함수 뒤에 const가 붙어 있다. 이는 getValue() 함수가 호출되더라도 MyClass 객체의 멤버 변수가 변경되지 않음을 보장한다. 반면, setValue() 함수는 const로 선언되지 않았으므로 value를 변경할 수 있다.

즉, 주로 getter 함수 뒤에 const를 붙인다고 보면 된다.