C++/PS

[C++ PS] 명품 C++ Programming 실습 문제 3장 풀이

Song 컴퓨터공학 2023. 7. 4. 17:08

명품 C++ Programming 교재 3장 클래스와 객체 실습문제 풀이입니다. 개인 풀이이므로 더 효율적인 풀이가 있을 수는 있으나 문제에서 요구하는 출력 조건은 모두 맞춘 해답 코드입니다.

 

 

Open Challenge 지수 표현 클래스 만들기. 실수의 지수 표현을 클래스 Exp로 작성하라. Exp.h 헤더 파일과 Exp.cpp 파일로 분리하여 작성하라.

// Open challenge. Exp.cpp 파일
#include <iostream>
using namespace std;

#include "Exp.h"

int main() {
	Exp a(3, 2);
	Exp b(9);
	Exp c;

	cout << a.getValue() << ' ' << b.getValue() << ' ' << c.getValue() << endl;
	cout << "a의 베이스 " << a.getBase() << ',' << "지수 " << a.getExp() << endl;

	if (a.equals(b))
		cout << "same" << endl;
	else
		cout << "not same" << endl;
}


// Exp.h 파일
#ifndef EXP_H
#define EXP_H

#include <iostream>
using namespace std;

class Exp {
private:
	int base;
	int exponent;
public:
	Exp() { base = 1; exponent = 0; }
	Exp(double num) { base = num, exponent = 1; }
	Exp(double n1, double n2) { base = n1; exponent = n2; }
	int getValue() {
		int result = base;
		for (int i = 1; i < exponent; i++) {
			result *= base;
		}
		return result;
	}
	int getBase() { return base; }
	int getExp() { return exponent; }
	bool equals(Exp b) { return (getValue() == b.getValue()) ? true : false; }
};

#endif

 

 

1. Tower() 클래스를 작성하라. (실행 결과와 main 함수 주어진 상태)

// 실습 1번
#include <iostream>
using namespace std;

class Tower
{
private:
	int height;
public:
	Tower() { height = 1; }
	Tower(int height) { this->height = height; }
	int getHeight() { return height; }
};

int main() {
	Tower myTower;
	Tower seoulTower(100);
	cout << "높이는 " << myTower.getHeight() << "미터" << endl;
	cout << "높이는 " << seoulTower.getHeight() << "미터" << endl;
}

 

 

2. 날짜를 다루는 Date 클래스를 작성하라. (실행 결과와 main 함수 주어진 상태)

// 실습 2번
#include <iostream>
#include <string>
using namespace std;


class Date {
private:
	int year;
	int month;
	int day;
public:
	Date();
	Date(int a, int b, int c) { year = a; month = b; day = c; }
	Date(string a);
	int getYear() { return year; }
	int getMonth() { return month; }
	int getDay() { return day; }
	void show();
};

Date::Date(string a) {
	int index;
	year = stoi(a);

	// substr(시작인덱스, 문자열길이) 에서 시작 인덱스만 명시해준다.
	index = a.find('/');
	month = stoi(a.substr(index + 1));

	index = a.find('/');
	day = stoi(a.substr(index + 1));
}

void Date::show() {
	cout << year << "년" << month << "월" << day << "일" << endl;
}

int main() {
	Date birth(2014, 3, 20);
	Date independenceDay("1945/8/15");
	independenceDay.show();
	cout << birth.getYear() << ',' << birth.getMonth() << ',' << birth.getDay() << endl;
}

파이썬의 split 에만 익숙해져있다보니 생각보다 문자열을 자르는 것이 까다로운 문제였습니다. 추후에 C++ 문자열 split 하는 방법들에 정리해서 올리도록 하겠습니다.

 

 

3. Account 클래스를 작성하라.  (실행 결과와 main 함수 주어진 상태)

// 실습 3번
#include <iostream>
#include <string>
using namespace std;

class Account {
private:
	string owner;
	int id;
	int balance;
public:
	Account(string owner, int id, int balance) { this->owner = owner; this->id = id; this->balance = balance; }
	string getOwner() { return owner; }
	int inquiry() { return balance; }
	void deposit(int m) { balance += m; }
	int withdraw(int m);
};

int Account::withdraw(int m)
{
	if (balance < m) {
		cout << "잔액이 부족합니다. " << endl;
		return 0;
	}
	balance -= m;
	return m;
}

int main() {
	Account a("Kitae", 1, 5000);
	a.deposit(50000);
	cout << a.getOwner() << "의 잔액은 " << a.inquiry() << endl;
	int money = a.withdraw(20000);
	cout << a.getOwner() << "의 잔액은 " << a.inquiry() << endl;
}

무난한 클래스 활용 문제입니다. 문제에서 요구하는 조건에는 없지만 withdraw 에서 잔액이 더 작은 경우 부족 메세지를 띄우도록 설정했습니다.

 

 

4. CoffeeMachine 클래스를 만들어라. 에스프레소 한 잔에는 커피와 물이 각각 1씩, 아메리카노의 경우 커피 1 물 2, 설탕 커피는 커피 1 물 2 설탕 1 이 소모된다. (main 함수와 출력 주어지는 문제)

// 실습 4번
#include <iostream>
#include <string>
using namespace std;

class CoffeeMachine {
private:
	int coffee;
	int water;
	int sugar;
public:
	CoffeeMachine(int coffee, int water, int sugar) { this->coffee = coffee; this->water = water; this->sugar = sugar; }
	void drinkEspresso() { coffee -= 1; water -= 1; }
	void drinkAmericano() { coffee -= 1; water -= 2; }
	void drinkSugarCoffee() { coffee -= 1; water -= 2; sugar -= 1; }
	void fill() { coffee = 10; water = 10; sugar = 10; }
	void show() { cout << "커피 머신 상태," << "\t커피:" << coffee << "\t물:" << water << "\t설탕:" << sugar << endl; }
};

int main() {
	CoffeeMachine java(5, 10, 3);
	java.drinkEspresso();
	java.show();
	java.drinkAmericano();
	java.show();
	java.drinkSugarCoffee();
	java.show();
	java.fill();
	java.show();
}

요구 출력 사항/예시에서 부족한 경우(커피, 물, 설탕이 0이하로 되는 경우)는 없었기 때문에 따로 구현하지 않았습니다. 

 

 

5. 랜덤 수를 발생시키는 Random 클래스를 만들어라. 

// 실습 5번
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

class Random {
public:
	Random();
	int next();
	int nextInRange(int low, int high);
};

Random::Random()
{
	// 랜덤 숫자 생성을 위한 시드 값을 설정하는 srand() 함수. 
	// 시드 값을 설정하지 않으면 rand() 함수는 항상 동일한 순서로 랜덤 숫자를 생성한다.
	srand(time(NULL));
}

int Random::next()
{
	int random_num = rand();
	return random_num;
}

int Random::nextInRange(int low, int high)
{
	int random_num = (rand() % (high - low + 1)) + low;
	return random_num;
}

int main()
{
	Random r;
	cout << "-- 0에서 " << RAND_MAX << "까지의 랜덤 정수 10 개--" << endl;
	for (int i = 0; i < 10; i++)
	{
		int n = r.next();
		cout << n << ' ';
	}
	cout << endl << endl << "-- 2에서 " << "4 까지의 랜덤 정수 10 개 --" << endl;
	for (int i = 0; i < 10; i++)
	{
		int n = r.nextInRange(2, 4);
		cout << n << ' ';
	}
	cout << endl;
}

 

 

6. 5번을 변형하여 짝수 정수만 발생시키는 EvenRandom 클래스를 작성하라.

// 실습 6번
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

class EvenRandom {
public:
	EvenRandom();
	int next();
	int nextInRange(int low, int high);
};

EvenRandom::EvenRandom()
{
	// 랜덤 숫자 생성을 위한 시드 값을 설정하는 srand() 함수. 
	// 시드 값을 설정하지 않으면 rand() 함수는 항상 동일한 순서로 랜덤 숫자를 생성한다.
	srand(time(NULL));
}

int EvenRandom::next()
{
	int random_num = 0;

	do {
		random_num = rand();
		// rand() > 0 ~ 32767(RAND_MAX) 까지의 난수 생성 (2의 15승 - 1 까지)
	} while (random_num % 2 != 0);

	return random_num;
}

int EvenRandom::nextInRange(int low, int high)
{
	int random_even = (rand() % ((high - low + 2) / 2) * 2) + low;
	return random_even;
}

int main()
{
	EvenRandom r;
	cout << "-- 0에서 " << RAND_MAX << "까지의 랜덤 짝수 정수 10 개--" << endl;
	for (int i = 0; i < 10; i++)
	{
		int n = r.next();
		cout << n << ' ';
	}
	cout << endl << endl << "-- 2에서 " << "10 까지의 랜덤 짝수 정수 10 개 --" << endl;
	for (int i = 0; i < 10; i++)
	{
		int n = r.nextInRange(2, 10);
		cout << n << ' ';
	}
	cout << endl;
}

 

 

7. 5번을 변형하여 짝수 홀수를 선택할 수 있도록 SelectableRandom 클래스를 작성하고 짝수 10개 홀수 10개를 랜덤하게 발생시키는 프로그램을 작성하라.

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

class SelectableRandom {
	int start;
	int end;
public:
	SelectableRandom();
	int next(int even_or_odd);
	int nextInRange(int start, int end, int even_or_odd);
};

SelectableRandom::SelectableRandom() {
	srand((unsigned int)time(NULL));
	start = 0;
	end = RAND_MAX;
}

int SelectableRandom::next(int even_or_odd) {
	int result;
	while (true) {
		result = rand() % (RAND_MAX + 1);
		if (result % 2 == even_or_odd) {
			return result;
		}
	}
}

int SelectableRandom::nextInRange(int start, int end, int even_or_odd) {
	int result;
	while (true) {
		result = rand() % (end - start + 1) + start;
		if (result % 2 == even_or_odd) {
			return result;
		}
	}
}
int main()
{
	SelectableRandom r;
	cout << "-- 0에서 " << RAND_MAX << "까지의 랜덤 짝수 10 개--" << endl;
	for (int i = 0; i < 10; i++)
	{
		int n = r.next(0); // 0 짝수
		cout << n << ' ';
	}
	cout << endl << endl << "-- 2에서 " << "9 까지의 랜덤 홀수 10 개 --" << endl;
	for (int i = 0; i < 10; i++)
	{
		int n = r.nextInRange(2, 9, 1); // 1 홀수
		cout << n << ' ';
	}
	cout << endl;
}

 

 

8. int 타입의 정수를 객체화한 Integer 클래스를 작성하라. Integer의 모든 멤버 함수를 자동 인라인으로 작성하라.

// 실습 8번
#include <iostream>
#include <string>
using namespace std;

class Integer {
private:
	int integer;
public:
	Integer() { integer = 1; }
	Integer(int num) { integer = num; }
	Integer(string num) { integer = stoi(num); }
	void set(int num) { integer = num; }
	int get() { return integer; }
	bool isEven() {
		return (integer % 2 == 0) ? true : false;
	}
};

int main()
{
	Integer n(30);
	cout << n.get() << ' ';
	n.set(50);
	cout << n.get() << ' ';

	Integer m("300");
	cout << m.get() << ' ';
	cout << m.isEven();
}

 

 

9. Oval 클래스는 주어진 사각형에 내접하는 타원을 추상화한 클래스이다. Oval 클래스의 멤버는 모두 다음과 같다.

  • 정수값의 사각형 너비와 높이를 가지는 width, height 변수 멤버
  • 너비와 높이 값을 매개 변수로 받는 생성자
  • 너비와 높이를 1로 초기화하는 매개 변수 없는 생성자
  • width와 height를 출력하는 소멸자
  • 타원의 너비를 리턴하는 getWidth() 함수 멤버
  • 타원의 높이를 리턴하는 getHeight() 함수 멤버
  • 타원의 면적을 리턴하는 getArea() 함수 멤버
  • 타원의 너비와 높이를 변경하는 set(int w, int h) 함수 멤버
  • 타원의 너비와 높이를 화면에 출력하는 show() 함수 멤버
// 실습 9번
#include <iostream>
using namespace std;

class Oval {
	int width, height;
	double getArea();
public:
	Oval() { width = height = 1; }
	Oval(int w, int h) { width = w; height = h; }
	~Oval() { cout << "Oval 소멸 : "; show(); }
	int getwidth() { return width; }
	int getHeight() { return height; }
	void set(int w, int h);
	void show();
};

inline double Oval::getArea()
{
	return 3.14 * width * height;
}
void Oval::set(int w, int h)
{
	width = w;
	height = h;
}
void Oval::show()
{
	cout << "width = " << getwidth() << ", height = " << getHeight() << "  Area = " << getArea() << endl;
}

int main()
{
	Oval a, b(3, 4);
	a.set(10, 20);
	a.show();
	b.show();
}

 

 

10. 더하기, 빼기, 곱하기, 나누기를 수행하는 4개의 클래스를 만들고 키보드로부터 두 개의 정수와 연산자를 입력 받아 a, s, m, d 객체 중에서 연산을 처리할 객체의 setValue() 함수를 호출한 후, calculate() 를 호출하여 결과를 화면에 출력한다.

// 실습 10번
#include <iostream>
using namespace std;

class Add {
private:
	int a;
	int b;
public:
	void setValue(int x, int y) { a = x; b = y; }
	int calculate() { return a + b; }
};

class Sub {
private:
	int a;
	int b;
public:
	void setValue(int x, int y) { a = x; b = y; }
	int calculate() { return a - b; }
};

class Mul {
private:
	int a;
	int b;
public:
	void setValue(int x, int y) { a = x; b = y; }
	int calculate() { return a * b; }
};

class Div {
private:
	int a;
	int b;
public:
	void setValue(int x, int y) { a = x; b = y; }
	int calculate() { return a / b; }
};

int main()
{
	Add a;
	Sub s;
	Mul m;
	Div d;
	int x, y;
	char op;
	while (1)
	{
		cout << "두 정수와 연산자를 입력하세요>>";
		cin >> x >> y >> op;
		if (op == '+') {
			a.setValue(x, y);
			cout << a.calculate() << endl;
		}
		else if (op == '-') {
			s.setValue(x, y);
			cout << s.calculate()<< endl;
		}
		else if (op == '*') {
			m.setValue(x, y);
			cout << m.calculate()<< endl;
		}
		else if (op == '/') {
			d.setValue(x, y);
			cout << d.calculate()<< endl;
		}
	}
}

 

 

11. 다음 코드에서 Box 클래스의 선언부와 구현부를 Box.h, Box.cpp 파일로 분리하고 main() 함수 부분을 main.cpp 부분으로 분리하여 전체 프로그램을 완성하라.

// Box.h
#ifndef BOX_H
#define BOX_H

#include <iostream>
using namespace std;

class Box {
private:
	int width, height;
	char fill;
public:
	Box(int w, int h);
	void setFill(char f);
	void setSize(int w, int h);
	void draw();
};
#endif


// Box.cpp
#include <iostream>
using namespace std;

#include "Box.h"

Box::Box(int w, int h) {
	setSize(w, h);
	fill = '*';
}
void Box::setFill(char f) {
	fill = f;
}
void Box::setSize(int w, int h) {
	width = w;
	height = h;
}
void Box::draw() {
	for (int n = 0; n < height; n++) {
		for (int m = 0; m < width; m++)
			cout << fill;
		cout << endl;
	}
}


// main.cpp
#include <iostream>
using namespace std;

#include "Box.h"

int main()
{
	Box b(10, 2);
	b.draw();
	cout << endl;
	b.setSize(7, 4);
	b.setFill('^');
	b.draw();
}

 

 

12. 컴퓨터의 주기억장치를 모델링하는 클래스 Ram을 구현하려고 한다. Ram 클래스는 데이터가 기록될 메모리 공간과 크기 정보를 가지고, 주어진 주소에 데이터를 기록하고(write), 주어진 주소로부터 데이터를 읽어 온다(read). Ram.h, Ram.cpp, main.cpp 로 분리하여 프로그램을 완성해라.

// Ram.h
#ifndef RAM_H
#define RAM_H

#include <iostream>
using namespace std;

class Ram {
	char mem[100 * 124];
	int size;
public:
	Ram();
	~Ram();
	char read(int address);
	void write(int address, char value);
};

#endif


// Ram.cpp
#include <iostream>
using namespace std;

#include "Ram.h"

Ram::Ram() {
	memset(mem, 0, 100*1024);
	size = 100 * 1024;
}

Ram::~Ram() {
	cout << "메모리 제거됨" << endl;
}

char Ram::read(int address) {
	return mem[address];
}

void Ram::write(int address, char value) {
	mem[address] = value;
}


// main.cpp