반응형

객체지향 프로그래밍의 개념

  • 프로그램에서 필요한 데이터 타입을 먼저 설계

  • C언어의 구조체를 사용하면 새로운 데이터 타입을 정의 가능

  • C 구조체 : 데이터만 포함 할 수 있음

  • C++ 구조체 : 데이터, 함수 포함 가능

C Style(구조체 없이 구현)

void Add(int xr, int xi, int yr, int yi, //in parameters
    int* sr, int* si) // out parameters
{
    *sr = xr + yr;
    *si = xi + yi;
}

int main()
{
    int ar = 1, ai = 1;
    int br = 2, bi = 2;
    int sr, si;

    Add(ar, ai, br, bi, &sr, &si);
}

C Style(구조체를 사용한 구현)

Complex Add(const Complex& c1, const Complex& c2)
{
    Complex temp;
    temp.re = c1.re + c2.re;
    temp.im = c1.im + c2.im;
    return temp;
}

int main()
{
    Complex c1 = { 1, 1 };
    Complex c2 = { 2, 2 };

    Complex t = Add(c1, c2);
}

 

Stack으로 배우는 OOP

Step1. 구조체 없이 전역으로 구현한 Stack

  • 쉽게 구현하였으나 Stack을 다중으로 사용하기에는 적절하지 않음

int buf[10];
int idx = 0;

void push(int n) { buf[idx++] = n; }
int pop() { return buf[--idx]; }

int main()
{
    push(10);
    push(20);
    push(30);

    std::cout << pop() << std::endl;
}

Step2. 구조체를 사용한 Stack

  • Stack 구조체를 사용하지 않았을때 보단 간결하지만 Stack 상태 조작 함수가 외부에 있음

struct Stack
{
    int buf[10];
    int idx;
};

void push(Stack* s, int n) 
{ 
    s->buf[(s->idx)++] = n; 
}
int pop(Stack* s) 
{ 
    return s->buf[--(s->idx)]; 
}

int main()
{
    Stack s1, s2;
    s1.idx = 0;
    s2.idx = 0;

    push(&s1, 10);
    push(&s1, 20);
    push(&s1, 30);

    std::cout << pop(&s1) << std::endl;
}

Step3. C++ 구조체를 사용한 Stack

  • 구조체에 데이터와 함수를 함께 구현

  • idx가 잘못된 값으로 초기화 위험성 있음
struct Stack
{
    int buf[10]; // 멤버 데이터
    int idx;

    void push(int n) // 멤버 함수
    {
        buf[idx++] = n;
    }
    int pop() // 멤버 함수
    {
        return buf[--idx];
    }
};

int main()
{
    Stack s1, s2;
    s1.idx = 0;
    s2.idx = 0;

    s1.push(10);
    s1.push(20); 
    s1.push(30); // 컴파일러에 의해서 내부적으로는 push(&s1, 20) 형태로 사용됨

    std::cout << s1.pop() << std::endl;
}

Step4. 정보 은닉(Information Hiding)

 

  • 접근 지정자
    • private : 멤버 함수에서만 접근 할 수 있음
    • public : 외부 함수에서 접근 가능
  • 정보 은닉(information hiding)
    • 멤버 데이터를 외부에서 직접 접근할 수 없게 하고, 멤버 함수를 통해서만 접근 가능하도록 함
    • 외부에 잘못된 사용으로 부터 객체가 불안해 지는것을 방지
    • Stack을 사용하는 사람은 push, pop 함수만 알면 되지 Stack  내부 데이터를 몰라도 됨
  • struct vs class
    • struct : 접근 지정자 생략시 기본 접근자 public
    • class : 접근 지정자 생략시 기본 접근자 private
class Stack
{
// class 접근 기본값은 private
    int buf[10];
    int idx;

public: // 외부 접근을 위한 public 접근자
    void init() { idx = 0; }
    void push(int n)
    {
        buf[idx++] = n;
    }
    int pop()
    {
        return buf[--idx];
    }
};

int main()
{
    Stack s1;
    s1.init();

    s1.push(10);
    s1.push(20);
    s1.push(30);

    std::cout << s1.pop() << std::endl;
}

Step5. 생성자(Constructor)

  • 클래스이름과 동일한 이름을 가지는 함수

  • 객체를 만들면 자동으로 생성자가 호출됨
  • 리턴 타입을 표지하지 않음
  • 인자 사용 여부는 선택적
class Stack
{
    int buf[10];
    int idx;

public:
    // 클래스 이름과 동일한 함수 : 생성자
    Stack() { idx = 0; }
    void push(int n) { buf[idx++] = n; }
    int pop() { return buf[--idx]; }
};

int main()
{
    Stack s1;

    s1.push(10);
    s1.push(20);
    s1.push(30);

    std::cout << s1.pop() << std::endl;
}

Step6. 소멸자(Destructor)

  • 스택의 버퍼크기를 변경 할 수 있도록 제공을 위해선 동적 메모리 할당이 필요한데 객체가 소멸되는 시점에 메모리 해지를 위해서 소멸자 이용
  • ~클래스이름() 형태의 함수

  • 객체가 파괴될 때 호출됨
class Stack
{
    int* buf;
    int idx;

public:
    // 생성자 : 객체가 생성될때 자동으로 호출
    Stack(int size = 10) 
    { 
        buf = new int[size]; // new 배열 타입으로 동적 메모리 할당
        idx = 0;
    }
    // 소멸자 : 객체가 파괴될때 자동으로 호출
    ~Stack() 
    {
        delete[] buf; // new 배열 타입으로 할당한 메모리를 delete[]로 해지
    }
    void push(int n) { buf[idx++] = n; }
    int pop() { return buf[--idx]; }
};

int main()
{
    Stack s1(20);
    s1.push(30);
    std::cout << s1.pop() << std::endl;
}

Step7. 선언과 구현의 분리

  • 선언과 구현의 분리

    • 클래스 선언 안에는 함수의 선언만 포함

    • 함수의 구현은 클래스 외부에서 구현

  • 선언 파일과 구현 파일의 분리

    • 클래스 선언부는 헤더 파일로 생성(.h)

    • 클래스 구현부는 소스 파일로 생성(.cpp)

// stack.h
class Stack
{
private:
    int* buf;
    int idx;

public:
    Stack(int size = 10);
    ~Stack();
    void push(int n);
    int pop();
};
// stack.cpp
#include "Stack.h"

Stack::Stack(int size = 10)
{
    buf = new int[size];
    idx = 0;
}
Stack::~Stack()
{
    delete[] buf;
}
void Stack::push(int n) 
{ 
    buf[idx++] = n; 
}
int Stack::pop() 
{ 
    return buf[--idx]; 
}
// main.cpp
#include <iostream>
#include "Stack.h"

int main()
{
    Stack s1(20);
    s1.push(30);
    std::cout << s1.pop() << std::endl;
}

Step8. 코딩 관례

  • 대부분의 오픈소스들은 프로젝트들은 사용자 친화적으로 public 함수를 상단, private 함수, 변수는 하단에 배치하는 경향을 보임

// Stack.h
class Stack
{
public: // 주 접근 함수를 상단
    Stack(int size = 10);
    ~Stack();
    void push(int n);
    int pop();
    
private: // 내부 접근 함수 및 변수는 하단
    int* buf;
    int idx;    
};

 

Step9. class template

  • Stack은 int 뿐 아니라 다른 타입버전도 필요하므로 템플릿을 이용하여 구현

  • 내부적으로는 컴파일 타임에 사용자 코드를 기반으로 각각의 데이터 타입별 Stack 클래스를 별도로 생성함
  • 클래스 템플릿에서 멤버 함수 구현시 주의사항
    • 클래스 외부, 내부에 구현부를 분리하여 넣어도 되지만, 별도의 소스파일로 분리하면 안됨
    • 함수 선언과 구현 모두 헤더파일에 존재 하여야함
template<typename T>
class Stack
{
    T* buf;
    int idx;

public:
    Stack(int size = 10) { 
        buf = new T[size];
    }
    ~Stack() {
        delete[] buf;
    }
    void push(T n) { buf[idx++] = n; }
    T pop() { return buf[--idx]; }
};

// 구현부 분리 시
template<typename T>
Stack<T>::Stack(){}

template<typename T> 
T Stack<T>::pop(){}


int main()
{
    Stack<int> s1(20);
    s1.push(30);

    Stack<double> s2(20);

    std::cout << s1.pop() << std::endl;
}

Step10. STL stack

  • STL

    • C++ 표준 라이브러리
    • 다양한 자료구조와 알고리즘 함수 제공
  • stack
    • 내부 버퍼 크기는 자동으로 관리됨
    • 템플릿으로 구현 됨
    • 제거용 함수와 리턴용 함수가 분리 되어 있음
      • pop : 제거만 하고 리턴 안됨
      • top : 리턴만 하고 제거되지 않음
int main()
{
    std::stack<int> s;
    s.push(10);
    s.push(20);
    s.push(30);

    int n1 = s.top(); // return 30(리턴만 하고 제거 X)
    int n2 = s.top(); // return 30(리턴만 하고 제거 X)
    s.pop(); // 제거만 하고 리턴 X
    int n3 = s.top(); // return 20
    s.pop(); // 제거만 하고 리턴 X
    int n4 = s.top(); // return 10
}

 

반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 복사 생성자  (0) 2019.05.06
C++ 접근 지정자, 생성자, 소멸자  (0) 2019.05.06
C++ Explicit Casting  (0) 2019.05.06
C++ reference 변수  (0) 2019.05.06
C++ new  (0) 2019.05.06

+ Recent posts