필자의 대학 코스 Advanced Programming에서 사용된 예시를 발췌, 정리했습니다. FINAL 시험에서 좋은 성과를 바라며…
Rectangle Class
rectangle.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <iostream>
class rectangle {
double width, height; // 멤버 변수
public:
rectangle(double w, double h) : width(w), height(h) {} // 생성자
double get_width() const { return this->width; } // 멤버 함수
double get_height() const { return this->height; } // 멤버 함수
};
std::ostream &operator<<(std::ostream &, rectangle const &);
#endif
rectangle.cpp
1
2
3
4
5
6
7
8
#include "rectangle.h"
using namespace std;
ostream &operator<<(ostream &out, rectangle const &r) {
return out << "rectangle (width:" << r.get_width() << ",height:" << r.get_height() << ")";
}
main.cpp
1
2
3
4
5
6
7
8
9
#include "rectangle.h"
#include <iostream>
int main() {
using namespace std;
rectangle r(10, 5);
cout << r << endl;
return 0;
}
출력
1
rectangle (width:10, height:5)
Bank Account Class
bank-account.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef BANK_ACCOUNT_H
#define BANK_ACCOUNT_H
class bank_account
{
unsigned long balance;
public:
bank_account(unsigned long b=0) : balance(b) {}
bank_account& operator+=(unsigned long);
unsigned long get_balance() const { return this->balance; }
bool transfer_to(bank_account &, unsigned long );
};
#include <iostream>
std::ostream& operator<<(std::ostream &, bank_account const &);
#endif
bank-account.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "bank-account.h"
bank_account& bank_account::operator+=(unsigned long amt)
{
this->balance += amt;
return *this;
}
bool bank_account::transfer_to(bank_account &other, unsigned long amt)
{
if (this->balance >= amt)
{
this->balance -= amt; // 여기는 되는 이유: 멤버 함수니까!
other.balance += amt;
return true;
}
else
{
return false;
}
}
using namespace std;
ostream& operator<<(ostream& out, bank_account const &accct)
{
return out << "Balance: " << acct.get_balance(); // 여기를 balance로 하면 안되는 이유: balances는 private 멤버 변수
}
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "bank-account.h"
#include <iostream>
using namespace std;
int main()
{
bank_account a;
bank_account b = 50;
a += 100;
b += 1000;
if (!a.transfer_to(b, 1))
cerr << "could not transfer money" << endl;
cout << a << endl << b << endl;
return 0;
}
출력
1
2
Balance: 99
Balance: 1051
Fraction Class
fraction.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef FRACTION_H
#define FRACTION_H
#include <iostream>
class fraction
{
int num;
unsigned denom;
public:
fraction(int num, unsigned denom=1) : num(num), denom(denom) {} // initializer list
fraction(fraction const &f) : num(f.num), denom(f.denom) {}
fraction& operator*=(fraction const &);
fraction operator*(fraction const &) const; // 관습적으로 쪼개서 구현한다! / 뒤에 붙는 const는, 값을 읽어서 반환만 하므로 (수정하지 않으므로) const가 붙는다
fraction& operator+=(fraction const &);
fraction operator+(fraction const &) const;
fraction& operator-=(fraction cons &) { return *this += -other; }
fraction operator-(fraction const &) const {return *this + -other; }
fraction operator-() const { return fraction(-num, denom); }
friend std::ostream& operator<<(std::ostream &, fraction const &); // 요친구는 fraction의 친구, 즉 fraction의 멤버 변수에 접근 가능
};
#endif
fraction.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "fraction.h"
fraction& fraction::operator*=(fraction const &other)
{
this->num *= other.num;
this->denom *= other.denom;
return *this;
}
fraction fraction::operator*(fraction const &other) const
{
fraction f = *this; // 복사 생성자 필요!
return f *= other; // 최대한 위에 쓴 걸 활용하자
}
fraction& fraction::operator+=(fraction const &other) {
unsigned new_denom = this->denom * other.denom;
this->num = this->num * other.denom + this->denom * other.num;
this->denom = new_denom;
return *this;
}
fraction fraction::operator+(fraction const &other) const {
fraction f = *this;
return f += other;
}
using namespace std;
ostream& operator<<(ostream& out, fraction const &f)
{
return out << f.num << "/" << f.denom;
}
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "fraction.h"
#include <iostream>
using namespace std;
int main()
{
fraction f = -2;
fraction g(5, 7);
cout << f << endl << g << endl;
cout << f * g << endl;
cout << f * g - 1 << endl;
return 0;
}
출력
1
2
3
4
-2/1
5/7
-10/7
-17/10
Set Class
set.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef SET_H
#define SET_H
#include <cstddef> // for size_t
class integer_set
{
int* elements;
size_t num_elements;
public:
integer_set();
~integer_set() { delete [] this->elements; }
integer_set& operator+=(int); // insert an int into the set
integer_set& operator-=(int); // remove an int from the set
bool operator[](int) const; // 있는지 없는지 체크
};
#endif
set.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "set.h"
integer_set::integer_set() : elements(new int[0]), num_elements(0) {}
integer_set::integer_set(integer_set const &other)
: elements(new int[other.num_elements]), num_elements(other.num_elements) {
for (size_t i = 0; i < this->num_elements; i++)
this->elements[i] = other.elements[i];
}
integer_set& integer_set::operator=(integer_set const &other) {
if (this->num_elements < other.num_elements) {
delete [] this->elements;
this->elements = new int[other.num_elements];
}
this->num_elements = other.num_elements;
for (size_t i = 0; i < this->num_elements; i++)
this->elements[i] = other.elements[i];
return *this;
}
integer_set& integer_set::operator+=(int val) {
if ((*this)[val]) return *this;
int* bigger = new int[this->num_elements + 1];
for (size_t i = 0; i < this->num_elements; i++)
bigger[i] = this->elements[i];
bigger[this->num_elements] = val;
delete [] this->elements;
this->elements = bigger;
this->num_elements++;
return *this;
}
integer_set& integer_set::operator-=(int val) {
if (!(*this)[val]) return *this;
int* val_location = this->elements;
for (size_t i = 0; i < this->num_elements; i++)
if (this->elements[i] == val)
val_location = &this->elements[i];
*val_location = this->elements[this->num_elements - 1];
this->num_elements--;
return *this;
}
bool integer_set::operator[](int val) const {
for (size_t i = 0; i < this->num_elements; i++)
if (this->elements[i] == val)
return true;
return false;
}
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "set.h"
#include <iostream>
int main() {
using namespace std;
integer_set s;
s += 1;
cout << "0 is in the set? " << s[0] << endl;
cout << "1 is in the set? " << s[1] << endl;
integer_set t = s;
t += 3;
cout << "3 is in the set? " << t[3] << endl;
s = t;
s += 2;
cout << "2 is in the set? " << s[2] << endl;
return 0;
}
출력
1
...
가변 길이 TEMPLATE을 이용한 SUM FUNCTION
가변 길이 템플릿의 구 버전
1
2
3
4
5
6
7
#define SUM_FUNCTION(tp) tp sum_ ## tp(tp const* arr, size_t n) { \
tp total = 0; \
for (size_t i = 0; i < n; i++) \
total += arr[i];
return total;
}
SUM_FUNCTION(int)
sum.h
1
2
3
4
5
6
7
8
#ifndef SUM_H
#define SUM_H
#include <cstddef>
template <typename T> T sum(T const *, size_t);
#include
sum.cc
1
2
3
4
5
6
7
8
9
10
#include "sum.h"
template <typename T> T sum(T const *xs, size_t n)
{
T total = 0;
for (size_t i = 0; i < n; i++) total += xs[i];
return total;
}
template int sum<int> (int const *, size_t);
main.cc
1
2
3
4
5
6
7
8
9
10
11
int main() {
using namespace std;
int x[] = { 3, 4, 5 };
cout << sum<int>(x, 3) << endl;
double y[] = { 9.5, 10, 10.5 };
cout << sum(y, 3) << endl;
value<double> a;
cout << a.get_value() << endl;
return 0;
}
출력
1
...
TEMPLATE을 이용한 LIST 클래스
list.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#ifndef LIST_H
#define LIST_H
#include <cstddef> // for size_t
template<typename T>
class list {
T* elements;
size_t num_elements;
public:
list() : elements(new T[0]), num_elements(0) {}
// rule of 3
~list() { delete [] elements; }
list(list const &) : elements(new T[other.num_elements]), num_elements(other.num_elements) {
for (size_t i = 0; i < this->num_elements; i++)
this->elements[i] = other.elements[i];
}
list& operator=(list const &){
delete [] elements;
this->num_elements = other.num_elements;
this->elements = new T[this->num_elements];
for (size_t i = 0; i < this->num_elements; i++)
this->elements[i] = other.elements[i];
return *this;
}
size_t length() const { return this->num_elements; }
T& operator[](size_t index) {
if (index >= this->num_elements) {
T* new_elements = new T[index + 1];
for (size_t i = 0; i < this->num_elements; i++)
new_elements[i] = this->elements[i];
delete [] this->elements;
this->elements = new_elements;
this->num_elements = index + 1;
}
return this->elements[index];
}
};
/*
* list<int> l;
* l[0] = 4; // adding something new to the list
* l[0]++; // modifying something in the list
* cout << l[0] << endl; // retrieving from the list
*/
#endif
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "list.h"
int main()
{
using namespace std;
list<int> l;
l[0] = 4;
l[0]++;
l[3] = l[0] * 9;
for (size_t i = 0; i < l.length(); i++)
cout << l[i] << " ";
cout << endl;
return 0;
}
STL:VECTOR 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector<int> v;
v.push_back(2);
v.push_back(3);
cout << v[0] << " " << v[1] << endl;
for (int x : v)
cout << x << endl;
return 0;
}
INHERITANCE: SHAPE CLASS
shape.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
enum col {black, red, white};
class shape
{
col colour;
public:
shape(col c) : colour(c) {}
virtual double area() const { return 0; }
virtual double perimeter() const { return 0; }
};
class circle : public shape {
double radius;
public:
circle(col c, double r) : shape(c), radius(r) {}
virtual double area() const
{
return 3.14 * this->radius * this->radius;
}
virtual double perimeter() const
{
return 2 * 3.14 * this->radius;
}
};
class triangle : public shape {
double base, height;
public:
triangle(col c, double b, double h) : shape(c), base(b), height(h) {}
virtual double area() const { return this->base * this->height / 2; }
};
int main()
{
using namespace std;
triangle t(col::red, 3, 4);
circle c(col::black, 5);
//shape s = c; // 부모에 자식 대입은 불가능!
shape& s = c; // 이건 가능
cout << t.area() << " " << c.area() << endl;
cout << t.perimeter() << " " << c.perimeter() << endl;
cout << s.area() << " " << s.perimeter() << endl; // virtual이 있기 때문에 c에 대한 정보로 처리, 없으면 s로 처리
return 0;
}
NUMBER CLASS
number.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
class number {
protected:
virtual double real_value() const = 0;
virtual double imaginary_value() const;
public:
virtual complex_number operator+(number const &other) const {
double r = this->real_value() + other.real_value();
double i = this->imaginary_value() + other.imaginary_value();
return complex_number(r, i);
}
};
class integer : public number {
int val;
public:
integer(int v) : val(v) {}
virtual double real_value() const { return this->val; }
virtual double imaginary_value() const { return 0; }
};
class real : public number {
double val;
public:
real(double v) : val(v) {}
virtual double real_value() const { return this->val; }
virtual double imaginary_value() const { return 0; }
};
class complex_number : public real {
double imag;
public:
complex_number(double r, double i) : real(r), imag(i) {}
virtual double imaginary_value() const { return 0; }
};
LIBRARY CLASS with ptr vector
library.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef LIBRARY_H
#define LIBRARY_H
#include <vector>
class library_item;
class library {
std::vector<library_item*> catalogue; // library_item is not defined! prototype
public:
library() : catalogue(std::vector<library_item*>()) {}
void add_library_item(library_item *);
int how_many_overdue(int days_after) const;
};
class library_item {
bool is_checked_out;
public:
virtual int borrowing_period() const { return 7; }
library_item() : is_checked_out(false) {}
virtual void loan() { this->is_checked_out = true; }
virtual void give_back() { this->is_checked_out = false; }
virtual bool can_borrow() const { return !this->is_checked_out; }
virtual bool is_late(int days_after) const {
return days_after > this->borrowing_period();
}
};
class book : public library_item {
public:
book() : library_item() {}
virtual int borrowing_period() const { return 14; }
};
class journal : public library_item {
public:
journal() : library_item() {}
};
#endif
library.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "library.h"
using namespace std;
void library::add_library_item(library_item *new_item) {
this->catalogue.push_back(new_item);
}
int library::how_many_overdue(int days_after) const {
int num_overdue = 0;
for (const library_item *li : this->catalogue) {
if (li->is_late(days_after))
num_overdue++;
}
return num_overdue;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include "library.h"
using namespace std;
int main() {
library l;
book b;
journal j;
b.loan();
j.loan();
l.add_library_item(&b);
l.add_library_item(&j);
cout << l.how_many_overdue(10) << endl;
return 0;
}
Problem: 이와 같은 메인함수를 작성해보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include "library.h"
using namespace std;
library* make_small_library() {
library* l = new library;
book b;
journal j;
b.loan();
j.loan();
l->add_library_item(&b);
l->add_library_item(&j);
return l;
}
int main() {
library* l = make_small_library(); // 에러가 나는 이유: 함수의 스택이 파괴되면서 안에 있는 멤버 변수들까지 파괴됨 (stack-buffer-underflow)
cout << l->how_many_overdue(10) << endl;
delete l;
return 0;
}
해결법: 1 catalogue
에 포인터 넣지 말고 클래스 자체를 넣기 2 b
와 j
를 힙에 넣어서 (new
, delete
) 스택이 파괴되어도 사라지지 않도록 하기 3 shared ptr
LIBRARY CLASS with shared ptr
library.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef LIBRARY_H
#define LIBRARY_H
#include <vector>
#include <memory>
class library_item;
class library {
std::vector<std::shared_ptr<library_item>> catalogue;
public:
library() : catalogue(std::vector<std::shared_ptr<library_item>>()) {}
void add_library_item(std::shared_ptr<library_item>);
int how_many_overdue(int days_after) const;
};
class library_item {
bool is_checked_out;
public:
virtual int borrowing_period() const { return 7; }
library_item() : is_checked_out(false) {}
virtual void loan() { this->is_checked_out = true; }
virtual void give_back() { this->is_checked_out = false; }
virtual bool can_borrow() const { return !this->is_checked_out; }
virtual bool is_late(int days_after) const {
return days_after > this->borrowing_period();
}
};
class book : public library_item {
public:
book() : library_item() {}
virtual int borrowing_period() const { return 14; }
};
class journal : public library_item {
public:
journal() : library_item() {}
};
#endif
library.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "library.h"
using namespace std;
void library::add_library_item(shared_ptr<library_item> new_item) {
this->catalogue.push_back(new_item);
}
int library::how_many_overdue(int days_after) const {
int num_overdue = 0;
for (const shared_ptr<library_item> li : this->catalogue) {
if (li->is_late(days_after))
num_overdue++;
}
return num_overdue;
}
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <memory>
#include "library.h"
using namespace std;
library* make_small_library() {
library* l = new library;
shared_ptr<book> b = shared_ptr<book>(new book);
shared_ptr<journal> j = shared_ptr<journal>(new journal);
b->loan();
j->loan();
l->add_library_item(b);
l->add_library_item(j);
return l;
}
int main() {
library* l = make_small_library();
cout << l->how_many_overdue(10) << endl;
delete l;
return 0;
}