티스토리 뷰
반응형
추가되는 기능
- 객체지향 프로그래밍에서 상위 클래스의 상속을 이용하여 다음과 같은 기능을 구현할 수 있다.
#include <iostream> class Base { public: virtual void foo() const { std::cout << "FOO" << std::endl; } }; class Derived1 : public Base { public: void foo() const override { std::cout << "BAR1" << std::endl; } }; class Derived2 : public Base { public: void foo() const override { std::cout << "BAR2" << std::endl; } }; class Derived3 : public Base { public: void foo() const override { std::cout << "BAR3" << std::endl; } }; class Derived4 : public Base { public: void foo() const override { std::cout << "BAR4" << std::endl; } }; void do_foo(const Base& b) { b.foo(); } int main() { Derived1 d1; Derived2 d2; Derived3 d3; Derived4 d4; do_foo(d1); do_foo(d2); do_foo(d3); do_foo(d4); return 0; }
BAR1 BAR2 BAR3 BAR4
각 하위 클래스가 서로 다른 foo를 반드시 구현할 때 더 이상 상위 클래스에서의 foo의 정의는 필요하지 않다. 하지만 정의하지 않았을 때 하위 클래스가 반드시 정의한다는 보장을 할 수 없으므로 정의를 비워둘 수 없다.
- 반드시 하위 클래스가 상위 클래스에 선언된 함수를 정의해야하고 상위 클래스에서 하위 클래스에서의 작동을 특정할 수 없을 때 순수 가상함수를 사용한다.
#include <iostream> class Base { public: virtual void foo() const = 0; };
이처럼 함수 정의 뒤에 '= 0'기호를 붙여주면 순수 가상함수의 선언이 된다. 순수 가상함수는 기능을 정의할 수 없으며 반드시 virtual 기호를 필요로 한다.
- 순수 가상함수를 선언한 클래스는 객체화할 수 없다.
#include <iostream> int main() { Base b; // error: cannot declare variable ‘b’ to be of abstract type ‘Base’ return 0; }
이렇듯 컴파일 에러가 발생한다. 이유는 함수 foo가 정의되지 않아 인스턴스 생성시 함수 foo을 호출했을 때의 작동이 보장되지 않기 때문이다. 이렇게 pure virtual function을 선언한 클래스를 추상 클래스(abstract class)이라 칭한다.
- 추상 클래스를 상속받은 모든 하위 클래스는 객체화하기 위해 반드시 순수 가상함수를 정의해야한다. 그렇지 않을 경우 그 클래스 또한 추상 클래스이다.
#include <iostream> class Base { public: virtual void foo() const = 0; }; class Derived : public Base {}; int main() { Derived d; // error: cannot declare variable ‘d’ to be of abstract type ‘Derived’ return 0; }
추상 클래스를 상속받은 하위 클래스 역시 기능을 구체화할 수 없고 다른 클래스가 재상속받아 정의할 경우 그 재상속 받은 클래스만 객체화할 수 있다.
#include <iostream> class Base { public: virtual void foo() const = 0; }; class Derived : public Base {}; class FarFarAway : public Derived { public: void foo() const override { std::cout << "foo" << std::endl; } }; int main() { FarFarAway f; // OK return 0; }
목표
- vector를 추상화한 class list를 정의한다.
디자인
- class list를 추가한다.
- list는 다음의 template parameter를 가진다.
- typename T
- list에 다음의 순수 가상함수를 추가한다.
- void add(T element)
- void add(int index, T element)
- T get(int element) const
- T set(int index, T element)
- T remove(int index)
- void print() const
- T& operator(int index)
- T operator(int index) = 0
- vector는 list를 상속받는다.
구현
#include <iostream>
#include <algorithm>
template<typename T>
class list {
public:
virtual void add(T element) = 0;
virtual void add(int index, T element) = 0;
virtual T get(int index) const = 0;
virtual T set(int index, T element) = 0;
virtual T remove(int index) = 0;
virtual void print() const = 0;
virtual T& operator[](int index) = 0;
virtual T operator[](int index) const = 0;
};
template<typename T, int INITIAL_SIZE = 10>
class vector : public list<T> {
private:
T* data;
int capacity;
int length;
bool ensure_capacity(int to_add) const {
return length + to_add < capacity;
}
void increase_capacity() {
auto tmp = data;
data = new T[capacity * 2];
std::copy(tmp, tmp + length, data);
delete[] tmp;
capacity *= 2;
}
void shiftLeft(int offset, int width) {
int tail_length = length - offset - width;
auto tail = new T[tail_length];
std::copy(data + offset + width, data + length, tail);
std::copy(tail, tail + tail_length, data + offset);
delete[] tail;
}
void shiftRight(int offset, int width) {
int tail_length = length - offset;
auto tail = new T[tail_length];
std::copy(data + offset, data + length, tail);
std::copy(tail, tail + tail_length, data + offset + width);
delete[] tail;
}
protected:
T* get_data() const {
return data;
}
public:
vector() {
data = new T[INITIAL_SIZE];
capacity = INITIAL_SIZE;
length = 0;
}
vector(const vector& v) {
data = new T[v.capacity];
capacity = v.capacity;
length = v.length;
std::copy(v.data, v.data + v.length, data);
}
~vector() {
delete[] data;
}
void add(T element) override {
if (!ensure_capacity(1))
increase_capacity();
*(data + length++) = element;
}
void add(int index, T element) override {
if (!ensure_capacity(1))
increase_capacity();
shiftRight(index, 1);
*(data + index) = element;
length++;
}
T get(int index) const override {
return *(data + index);
}
T set(int index, T element) override {
auto tmp = *(data + index);
*(data + index) = element;
return tmp;
}
T remove(int index) override {
auto tmp = *(data + index);
shiftLeft(index, 1);
length--;
return tmp;
}
void print() const override {
std::cout << '{';
for (int i = 0; i < length; i++)
std::cout << *(data + i) << ((i < length - 1) ? ", " : "");
std::cout << '}' << std::endl;
}
vector& operator=(const vector& v) {
data = new T[v.capacity];
capacity = v.capacity;
length = v.length;
std::copy(v.data, v.data + capacity, data);
return *this;
}
vector& operator+=(T element) {
add(element);
return *this;
}
T& operator[](int index) override {
return *(data + index);
}
T operator[](int index) const override {
return *(data + index);
}
};
template<typename T>
void list_print(const list<T>& l) {
l.print();
}
int main() {
vector<int> v;
v.add(10);
v.add(20);
v.add(30);
v.add(40);
v.add(50);
list_print(v);
return 0;
}
반응형
'C++ > C to C++' 카테고리의 다른 글
[C to C++] 상속 - 생존주기, 가상함수 (0) | 2019.02.02 |
---|---|
[C to C++] 상속 (0) | 2019.02.01 |
[C to C++] 템플릿 (0) | 2019.02.01 |
[C to C++] friend, 연산자 오버로딩 (0) | 2019.01.31 |
[C to C++] 함수 오버로딩 (0) | 2019.01.31 |
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- Java
- LG
- d802
- c++ struct
- g2 korea
- dokdo 4.0.3
- Kotlin
- nodeal
- CM10.2
- vector
- f320s
- PipelineContext
- 객체지향
- 포인터
- cyanogenmod
- C
- C++ 업캐스팅
- c++11
- OOP
- linaro
- rule_of_three
- dokdo-project
- C++
- rule_of_five
- c++ 상속
- CM11
- f320k
- G2
- dokdo project
- inline class
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함