1. 두 개의 Circle 객체를 교환하는 swap() 함수를 '참조에 의한 호출'이 되도록 작성하고 호출하는 프로그램을 작성하라.
<실행화면>
<소스코드>
// prac5-1
#include <iostream>
using namespace std;
class Circle {
int radius;
public:
Circle() { this->radius = 1; }
Circle(int r) { this->radius = r; }
int getRadius() { return this->radius; }
void setRadius(int r) { this->radius = r; }
void swap(Circle& x, Circle& y);
};
void Circle::swap(Circle& x, Circle& y) {
Circle tmp;
tmp = x;
x = y;
y = tmp;
}
int main() {
Circle a(5), b(10);
cout << "a의 반지름: " << a.getRadius() << endl;
cout << "b의 반지름: " << b.getRadius() << endl;
swap(a, b);
cout << "a의 반지름: " << a.getRadius() << endl;
cout << "b의 반지름: " << b.getRadius() << endl;
return 0;
}
2. 다음 main() 함수의 실행 결과를 참고하여 half() 함수를 작성하라.
<실행화면>
<소스코드>
// prac5-2
#include <iostream>
using namespace std;
double half(double& num) {
return num /= 2;
}
int main() {
double n = 20;
half(n);
cout << n;
return 0;
}
3. 다음과 같이 작동하도록 Combine() 함수를 작성하라.
<실행화면>
<소스코드>
// prac5-3
#include <iostream>
#include <string>
using namespace std;
string combine(string& text1, string& text2, string& text3) {
return text3 = text1 + ' ' + text2;
}
int main() {
string text1("I love you"), text2("very much");
string text3;
combine(text1, text2, text3);
cout << text3; // "I love you very much" 출력
return 0;
}
4. 아래와 같이 원형으로 주어진 bigger()를 작성하고 사용자로부터 2개의 정수를 입력받아 큰 값을 출력하는 main()을 작성하라. bigger()는 인자로 주어진 a, b가 같으면 true, 아니면 false를 리턴하고 큰 수는 big에 전달한다.
<실행화면>
<소스코드>
// prac5-4
#include <iostream>
using namespace std;
bool bigger(int a, int b, int& big) {
if (a == b)
return true;
else {
big = a > b ? a : b;
return false;
}
}
int main() {
int a, b, big = 0;
cout << "input a b: ";
cin >> a >> b;
if (bigger(a, b, big)) //bigger()==1 이면
cout << "a = b = " << a << endl;
else
cout << "big = " << big << endl;
return 0;
}
5. 다음 Circle 클래스가 있다.
class Circle
{
int radius;
public:
Circle(int r) { radius = r;}
int getRadius() { return radius; }
void setRadius(int r) { radius = r; }
void show() { cout << "반지름이 " << radius << "인 원" << endl; }
};
Circle 객체 b를 a에 더하여 a를 키우고자 increasedBy() 함수를 작성하였다.
void increasedBy(Circle a, Circle b)
{
int r = a.getRadius() + b.getRadius();
a.setRadius(r);
}
다음 코드를 실행하면, increaseBy() 함수는 목적대로 실행되는가?
int main()
{
Circle x(10), y(5);
increasedBy(x, y);
x.show();
}
main() 함수의 목적을 달성하도록 increaseBy() 함수를 수정하라.
<실행화면>
<소스코드>
// prac5-5
#include <iostream>
using namespace std;
class Circle
{
int radius;
public:
Circle(int r) { radius = r; }
int getRadius() { return radius; }
void setRadius(int r) { radius = r; }
void show() { cout << "반지름이 " << radius << "인 원" << endl; }
};
void increasedBy(Circle &a, Circle &b)
{
int r = a.getRadius() + b.getRadius();
a.setRadius(r);
}
int main()
{
Circle x(10), y(5);
increasedBy(x, y);
x.show();
return 0;
}
increasedBy(Circle &a, Circle &b)의 a와 b는 복사본이 아닌 원본 객체를 참조하는 참조 매개 변수이므로, a.setRadius(r)가 호출되면 a 객체의 반지름 값이 수정된다.
6. find() 함수의 원형은 다음과 같다. 문자열 a에서 문자 c를 찾아 문자 c가 있는 공간에 대한 참조를 리턴한다. 만일 문자 c를 찾을수 없다면 success 참조 매개 변수에 false를 설정한다. 물론 찾게 되면 success에 true를 설정한다.
char& find(char a[], char c, bool& success);
<실행화면>
<소스코드>
// prac5-6
#include <iostream>
using namespace std;
char& find(char a[], char c, bool& success) {
for (int i = 0; a[i] != '\0'; i++) {
if (a[i] == c) {
success = true;
return a[i];
}
}
success = false;
static char dummy = '\0'; // 안전한 리턴값
return dummy;
}
int main() {
char s[] = "Mike";
bool b = false;
char& loc = find(s, 'M', b);
if (b == false) {
cout << "M을 발견할 수 없다" << endl;
return 0;
}
loc = 'm'; // 'M' 위치에 'm' 기록
cout << s << endl; // "mike"가 출력됨
}
dummy = 임시 대체용 가짜. 안전하게 형식만 맞추기 위한 변수.
7. 다음과 같이 선언된 정수를 정수를 저장하는 스택 클래스 MyIntStack을 구현하라. MyIntStack 스택에 저장할 수 있는 정수의 최대 개수는 10개이다.
<실행화면>
<소스코드>
// prac5-7
#include<iostream>
using namespace std;
class MyIntStack
{
int p[10]; // 최대 10개의 정수 저장
int tos = 0; // 스택의 꼭대기를 가리키는 인덱스
public:
MyIntStack();
bool push(int n); // 정수 n 푸시. 꽉 차 있으면 flase, 아니면 true 리턴
bool pop(int& n); // 팝하여 n에 저장. 스택이 비어 있으면 false, 아니면 true 리턴
};
MyIntStack::MyIntStack() { // 기본 생성자 함수. p[]의 각 원소를 0으로 초기화
for (int i = 0; i < 10; i++)
p[i] = 0;
}
bool MyIntStack::push(int n) {
if (tos > 9) return false;
else {
p[tos++] = n;
return true;
}
}
bool MyIntStack::pop(int& n) {
if (tos <= 0) return false;
else {
n = p[--tos];
return true;
}
}
int main()
{
MyIntStack a;
for (int i = 0; i < 11; i++) // 11개를 푸시하면, 마지막에는 stack full이 된다.
{
if (a.push(i)) cout << i << ' '; // 푸시된 값 에코
else
cout << endl << i + 1 << "번째 stack full" << endl;
}
int n;
for (int i = 0; i < 11; i++) // 11개를 팝하면, 마지막에는 stack empty가 된다.
{
if (a.pop(n)) cout << n << ' '; // 팝 한 값 출력
else cout << endl << i + 1 << "번째 stack empty";
}
cout << endl;
return 0;
}
8. 문제 7번의 MyIntStack를 수정하여 다음과 같이 선언하였다. 스택에 저장할 수 없는 정수의 최대 개수는 생성자에서 주어지고 size 멤버에 유지한다. MyIntStack 클래스를 작성하라.
<실행화면>
<소스코드>
// prac5-8
#include <iostream>
using namespace std;
class MyIntStack
{
int *p; // 스택 메모리로 사용할 포인터
int size; // 스택의 최대 크기
int tos; // 스택의 탑을 가리키는 인덱스
public:
MyIntStack() = delete; // 디폴트 생성자 금지. 매개 변수 있는 생성자만 허용
MyIntStack(int size);
MyIntStack(const MyIntStack& s); // 복사 생성자
~MyIntStack(); // 소멸자
bool push(int n); // 정수 n 푸시. 꽉 차 있으면 flase, 아니면 true 리턴
bool pop(int& n); // 팝하여 n에 저장. 스택이 비어 있으면 false, 아니면 true 리턴
};
MyIntStack::MyIntStack(int size) {
this->size = size;
this->tos = 0;
this->p = new int[this->size];
if (!p) { // 메모리 할당 실패 시
cout << "동적 할당 실패" << endl; // 경고 메시지 출력
exit(0); // 프로그램 종료
}
}
MyIntStack::MyIntStack(const MyIntStack& s) {
this->size = s.size;
this->tos = s.tos;
this->p = new int[s.size];
for (int i = 0; i < s.tos; i++)
this->p[i] = s.p[i];
}
MyIntStack::~MyIntStack() {
if (this->p) // 동적 할당된 메모리가 있으면
delete[] p; // 메모리 해제. 힙에 반환
}
bool MyIntStack::push(int n) {
if (tos >= this->size) return false;
else {
p[tos++] = n;
return true;
}
}
bool MyIntStack::pop(int& n) {
if (tos <= 0) return false;
else {
n = p[--tos];
return true;
}
}
int main() {
MyIntStack a(10);
a.push(10);
a.push(20);
MyIntStack b = a;
b.push(30);
int n;
a.pop(n);
cout << "스택 a에서 팝한 값 " << n << endl;
b.pop(n);
cout << "스택 b에서 팝한 값 " << n << endl;
return 0;
}
9. 클래스 Accumulator는 add() 함수를 통해 계속 값을 누적하는 클래스로서, 다음과 같이 선언된다. Accumulator 클래스를 구현하라.
<실행화면>
<소스코드>
// prac5-9
#include <iostream>
using namespace std;
class Accumulator {
int value;
public:
Accumulator(int value) { this->value = value; }
Accumulator& add(int n); // value에 n을 더해 값을 누적한다.
int get() { return this->value; } // 누적된 값 value를 리턴한다.
};
Accumulator& Accumulator::add(int n) {
value += n;
return *this; // 자기 자신의 참조를 리턴
}
int main() {
Accumulator acc(10);
acc.add(5).add(6).add(7);
cout << acc.get();
return 0;
}
10. 참조를 리턴하는 코드를 작성해보자. 다음 코드와 실행 결과를 참고하여 append() 함수를 작성하고, 전체 프로그램을 완성하라. append()는 Buffer 객체에 문자열을 추가하고 Buffer 객체에 대한 참조를 반환하는 함수이다.
<실행화면>
<소스코드>
// prac5-10
#include <iostream>
#include <string>
using namespace std;
class Buffer {
string text;
public:
Buffer(string text) { this->text = text; }
void add(string next) { text += next; }
void print() { cout << text << endl; }
};
Buffer& append(Buffer& b, string str) {
b.add(str);
return b; // b객체에 대한 참조(공간) 리턴
}
int main() {
Buffer buf("Hello");
Buffer& temp = append(buf, "Guys");
temp.print();
buf.print();
cout << endl;
return 0;
}
11. 책의 이름과 가격을 저장하는 다음 Book 클래스에 대해 물음에 답하라.
class Book {
char* title; // 제목 문자열
int price; //가격
public:
Book(const char* title, int price);
~Book();
void set(char* title, int price);
void show() { cout << title << ' ' << price << "원" << endl; }
};
(1) Book 클래스의 생성자, 소멸자, set() 함수를 작성하라. set() 함수는 멤버 변수 title에 할당된 메모리가 있으면 먼저 반환한다. 그러고 나서 새로운 메모리를 할당받고 이곳에 매개 변수로 전달받은 책 이름을 저장한다.
<소스코드>
Book::Book(const char* title, int price) { // 생성자
int len = strlen(title);
this->title = new char[len + 1];
if (!this->title) {
cout << "동적 할당 실패" << endl;
exit(0);
}
strcpy(this->title, title);
this->price = price;
}
Book::~Book() { // 소멸자
delete[] title;
}
void Book::set(char* title, int price) {
delete[] title; // 멤버 변수 title에 할당된 메모리가 있으면 먼저 반환
int len = strlen(title);
this->title = new char[len + 1]; // 새로운 메모리를 할당 받고
if (!this->title) {
cout << "동적 할당 실패" << endl;
exit(0);
}
strcpy(this->title, title); // 이곳에 매개 변수로 전달받은 책이름을 저장한다.
this->price = price;
}
(2) 컴파일러가 삽입하는 디폴트 복사 생성자 코드는 무엇인가?
<소스코드>
Book::Book(const Book& b) { // 디폴트 복사 생성자
this->title = b.title;
this->price = b.price;
}
(3) 디폴트 복사 생성자만 있을 때 다음 main() 함수는 실행 오류가 발생한다. 정상적으로 실행하도록 깊은 복사 생성자를 작성하라.
int main() {
Book cpp("명품 C++", 10000);
Book java = cpp;
java.set("명품자바", 12000);
cpp.show();
java.show();
}
<실행화면>
<소스코드>
Book::Book(const Book& b) { // 깊은 복사 생성자
int len = strlen(b.title);
this->title = new char[len + 1];
strcpy(this->title, b.title);
this->price = b.price;
}
// prac5-11
// C-stirng 사용
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class Book {
char* title; // 제목 문자열
int price; //가격
public:
Book(const char* title, int price);
Book(const Book& b);
~Book();
void set(const char* title, int price);
void show() { cout << title << ' ' << price << "원" << endl; }
};
Book::Book(const char* title, int price) { // 생성자
int len = strlen(title);
this->title = new char[len + 1];
if (!this->title) {
cout << "동적 할당 실패" << endl;
exit(0);
}
strcpy(this->title, title);
this->price = price;
}
Book::Book(const Book& b) { // 깊은 복사 생성자
int len = strlen(b.title);
this->title = new char[len + 1];
strcpy(this->title, b.title);
this->price = b.price;
}
Book::~Book() { // 소멸자
delete[] this->title;
}
void Book::set(const char* title, int price) {
delete[] this->title; // 멤버 변수 title에 할당된 메모리가 있으면 먼저 반환
int len = strlen(title);
this->title = new char[len + 1]; // 새로운 메모리를 할당 받고
if (!this->title) {
cout << "동적 할당 실패" << endl;
exit(0);
}
strcpy(this->title, title); // 이곳에 매개 변수로 전달받은 책이름을 저장한다.
this->price = price;
}
int main() {
Book cpp("명품 C++", 10000);
Book java = cpp;
java.set("명품자바", 12000);
cpp.show();
java.show();
}
(4) 문제 (3)에서 실행 오류가 발생하는 원인은 Book 클래스에서 C-string(char* title) 방식으로 문자열을 다루었기 때문이다. 복사 생성자를 작성하지 말고 문자열을 string 클래스를 사용하여, 문제 (3)의 실행 오류가 발생하지 않도록 Book 클래스를 수정하라. 이 문제를 풀고 나면 문자열을 다룰 때, string을 사용해야 하는 이유를 명확히 알게 될 것이다.
<실행화면>
<소스코드>
// prac5-11
// string 사용. 클래스 내부에서 자동으로 동적 메모리를 처리하므로 소멸자 필요 없이 자동으로 관리됨.
// 메모리 누수 걱정 없음
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Book {
string title; // 제목 문자열
int price; // 가격
public:
Book(string title, int price) { this->title = title; this->price = price; }
void set(string title, int price) { this->title = title; this->price = price; }
void show() { cout << title << ' ' << price << "원" << endl; }
};
int main() {
Book cpp("명품 C++", 10000);
Book java = cpp;
java.set("명품자바", 12000);
cpp.show();
java.show();
}
12. 학과를 나타내는 Dept 클래스와 이를 활용하는 main()을 보여준다.
(1) main()의 실행 결과가 다음과 같이 실행되도록 Dept 클래스에 멤버들을 모두 구현하고, 전체 프로그램을 완성하라.
<실행화면>
<소스코드>
// prac5-12
// Dept.h
#ifndef DEFT_H
#define DEFT_H
#include <iostream>
using namespace std;
class Dept {
int size; // scores 배열의 크기
int* scores; // 동작 할당 받을 정수 배열의 주소
public:
Dept(int size) { // 생성자
this->size = size;
scores = new int[size];
}
Dept(const Dept& dept); // 복사 생성자
~Dept(); // 소멸자
int getSize() { return size; }
void read(); //size 만큼 키보드에서 정수를 읽어 scores 배열에 저장
bool isOver60(int index); // index의 학생의 성적이 60보다 크면 true 리턴
};
#endif // !DEFT_H
// prac5-12
// countPass.h
#ifndef COUNTPASS_H
#define COUNTPASS_H
#include "Dept.h"
int countPass(Dept dept);
#endif // !COUNTPASS_H
// prac5-12
// Dept.cpp
#define _CRT_SECURE_NO_WARNING
#include "Dept.h"
Dept::Dept(const Dept& dept) {
this->size = dept.size;
this->scores = new int[dept.size];
for (int i = 0; i < dept.size; i++) {
this->scores[i] = dept.scores[i]; // 배열 값 복사
}
}
Dept::~Dept() {
delete[] scores;
}
void Dept::read() {
cout << this->size << "개 점수 입력>> ";
for (int i = 0; i < this->size; i++)
cin >> scores[i];
}
bool Dept::isOver60(int index) {
if (scores[index] > 60) return true;
else return false;
}
#include "countPass.h"
int countPass(Dept dept) { // dept 학과에 60점 이상으로 통과하는 학생의 수 리턴
int count = 0;
for (int i = 0; i < dept.getSize(); i++) {
if (dept.isOver60(i)) count++;
}
return count;
}
// prac5-12
// main.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "Dept.h"
#include "countPass.h"
using namespace std;
int main() {
Dept com(10); // 총 10명이 있는 학과 com
com.read(); // 총 10명의 학생들의 성적을 키보드로부터 읽어 scores 배열에 저장
int n = countPass(com); // com 학과에 60점 이상으로 통과한 학생의 수를 리턴
cout << "60점 이상은 " << n << "명" << endl;
}
(2) Dept 클래스에 복사 생성자 Dept(const Dept& dept); 가 작성되어 있지 않은 경우, 컴파일은 되지만 프로그램 실행 끝에 실행 시간 오류가 발생한다. (복사 생성자를 뺀 채 실행해 보라). 위의 코드 어느 부분이 실행될 때 복사 생성자가 호출되는지 설명하고, 복사 생성자가 없으면 왜 실행오류가 발생하는지 설명하라.
<실행화면>
<소스코드>
int countPass(Dept dept) { // dept 학과에 60점 이상으로 통과하는 학생의 수 리턴
int count = 0;
for (int i = 0; i < dept.getSize(); i++) {
if (dept.isOver60(i)) count++;
}
return count;
}
따라서 countPass(com) 호출 시 컴파일러가 자동 생성한 기본 복사 생성자가 실행되어, 값에 의한 호출이 일어난다.
(3) Dept 클래스에 복사 생성자를 제거하라. 복사 생성자가 없는 상황에서도 실행오류가 발생하지 않게 하려면 어느 부분을 수정하면 될까? 극히 일부분의 수정으로 해결된다. 코드를 수정해보라.
<소스코드>
int countPass(Dept &dept) { // 참조에 의한 호출 형식으로 변경
int count = 0;
for (int i = 0; i < dept.getSize(); i++) {
if (dept.isOver60(i)) count++;
}
return count;
}
[객체지향언어1] 명품 C++ Programming 7장 실습 문제 (0) | 2025.06.15 |
---|---|
[객체지향언어1] 명품 C++ Programming 6장 실습 문제 (2) | 2025.06.14 |
[객체지향언어1] 명품 C++ 프로그래밍 4장 Open Challenge (0) | 2025.04.13 |
[객체지향언어1] 명품 C++ Programming 3장 실습 문제 (0) | 2025.04.08 |
[객체지향언어1] 명품 C++ Programming 2장 실습 문제 (0) | 2025.04.06 |