티스토리 뷰

C++/C to C++

[C to C++] 상속

nodeal 2019. 2. 1. 13:17

추가되는 기능

    • 정의된 class의 기능을 재정의하거나 확장하고자 할 때 해당 class를 상속할 수 있다.
    • 상속받은 class(이하 'Derived')는 상속되는 class(이하 'Base')의 모든 기능을 포함하고 있다.
      #include <iostream>
      
      class Base {
          private:
          int value;
          
          public:
          int get() const {
              return value;
          }
          
          void set(int value) {
              this->value = value;
          }
      };
      
      class Derived : public Base {};
      //              ^^^^^^ ^^^^
      
      int main() {
          Derived d;
          d.set(10);
          std::cout << d.get() << std::endl;
          
          return 0;
      }
      
    • Derived는 Base의 기능을 부분적으로 재정의(override)할 수 있다.

      class Derived : public Base { private: int d_value; public: void set_d(int d_value) { this->d_value = d_value; } int get() const { return Base::get() * d_value; } }; int main() { Derived d; d.set(10); d.set_d(2); std::cout << d.get() << std::endl; return 0; }

    • Derived는 Base이지만, Base는 Derived가 아니다.
      Derived d1;
      d1.set(10);
      Base b1 = d1; // OK
      std::cout << b1.get() << std::endl;
      
      Base b2;
      Derived d2 = b2; // Error
      
    • 하위 class에서 상위 class로의 up-casting은 데이터 유실을 일으킬 수 있고, 상위 class에서 하위 class로의 down-casting은 없는 값을 만들어낼 수 없기에 불가능하다.

    • 접근 지정자 protected로 선언된 멤버 변수, 함수는 하위 class에서만 호출될 수 있다. 이때, this 기호를 사용하여 호출해야한다.
      class Base {
          protected:
          int value;
          
          public:
          int get() const {
              return value;
          }
          
          void set(int value) {
              this->value = value;
          }
      };
      
      class Derived : public Base {
          public:
          int get() const {
              return this->value * 2;
          }
      };
      
      class FarFarAway : public Derived {
          public:
          int get() const {
              return this->value;
          }
      };
      
      int main() {
          FarFarAway f;
          f.set(10);
          Derived d = f;
          std::cout << d.get() << std::endl;
          std::cout << f.get() << std::endl;
          
          return 0;
      }
      
    • Base가 template class인 경우, template parameter를 만족시켜야한다.
      template<typename T>
      class Base {
          protected:
          T value;
          
          public:
          T get() const {
              return value;
          }
          
          void set(T value) {
              this->value = value;
          }
      };
      
      template<typename T = int>
      class Derived : public Base<T> {
          public:
          T get() const {
              return this->value * 2;
          }
      };
      
      class FarFarAway : public Derived<long> {
          public:
          long get() const {
              return this->value;
          }
      };
      
      int main() {
          FarFarAway f;
          f.set(10);
          Derived d = f;
          std::cout << d.get() << std::endl;
          std::cout << f.get() << std::endl;
          
          return 0;
      }

목표

    • vector를 상속받는 class char_seq를 정의한다.
      char_seq는 char형의 배열을 갖는 자료구조로, 출력시 배열의 꼴이 아닌 문자열의 꼴로 출력한다.

디자인

    • char_seq: 다음 class를 추가한다.
      template<int INITIAL_SIZE = 10> class char_seq : public vector<char, INITIAL_SIZE>
    • char_seq: 다음 멤버 함수가 override된다.
      void print() const
    • vector: 다음 멤버 함수를 추가한다.
      protected: T* get_data() const
      멤버 변수 data를 반환한다.

구현

#include <iostream>
#include <algorithm>

template<typename T, int INITIAL_SIZE = 10>
class vector {
    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) {
        if (!ensure_capacity(1))
            increase_capacity();
        
        *(data + length++) = element;
    }
    
    void add(int index, T element) {
        if (!ensure_capacity(1))
            increase_capacity();
        
        shiftRight(index, 1);
        *(data + index) = element;
        length++;
    }
    
    T get(int index) const {
        return *(data + index);
    }
    
    T set(int index, T element) {
        auto tmp = *(data + index);
        *(data + index) = element;
        return tmp;
    }
    
    T remove(int index) {
        auto tmp = *(data + index);
        shiftLeft(index, 1);
        length--;
        
        return tmp;
    }
    
    void print() const {
        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) {
        return *(data + index);
    }
    
    T operator[](int index) const {
        return *(data + index);
    }
};

template<int INITIAL_SIZE = 10>
class char_seq : public vector<char, INITIAL_SIZE> {
    public:
    void print() const {
        std::cout << this->get_data() << std::endl;
    }
};

int main() {
    vector<char> v;
    v.add('H');
    v.add('e');
    v.add('l');
    v.add('l');
    v.add('o');
    v.print();
    
    char_seq seq;
    seq.add('H');
    seq.add('e');
    seq.add('l');
    seq.add('l');
    seq.add('o');
    seq.print();
    
    return 0;
}

{H, e, l, l, o}
Hello

'C++ > C to C++' 카테고리의 다른 글

[C to C++] 상속 - 순수 가상함수, 추상 클래스  (0) 2019.02.03
[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
댓글
댓글쓰기 폼