개체지향 프로그래밍1

OOP 란?

  • "사람들이 세상을 바라보는 방식" = OOP 의 핵심개념

접근제어자

  • C++ 의 접근제어자는 private, protected, public 이 있다.

  • C++ 기본 접근 권한은 private 이다. (Java 의 경우 기본 접근 권한은 패키지 내 접근 가능이다)

  • 보통 다음 코드와 같이 접근제어자 별로 멤버들을 그룹짓는다.

class SomeClass
{
    public:
        int mPublicMember;
    protected:
        int mProtectedMember;
    private:
        int mPrivateMember1;
        int mPrivateMember2;
};

개체 생성

  • 스택

    • 스택 포인터만 변경하면 되기 때문에, 속도가 빠르다.

    • exe 파일 생성시 별도의 설정이 없다면, 1MB 를 스택으로 사용한다.

    • 기본적으로 힙 메모리를 사용하는 것은 스택에 비해 느리다.

    • 운영체제에 클래스 객체가 생성될 수 있는 메모리 공간을 확인해야 하기 때문에, 느리다..

스택과 힙

C++ 은 스택에 객체를 생성할 수 있다고 했는데, 스택은 무엇일까?

  • 예약 된 로컬 메모리 메모리 공간(작음, 보통 1MB 미만이다) -> 오브젝트 크기가 작다면 개체를 스택에 생성하는 것이 무조건 유리하다. -> 컴파일러 설정을 통해 스택 메모리 크기를 지정할 수 있다. -> 컴파일을 한 .exe 파일 실행할 때, 메모리에 .exe 파일이 올라가고 일반적으로 1MB를 스택으로 사용한다.

  • 함수 호출과 반환이 이 메모리에서 일어난다.

  • 단순히 스택 포인터를 옮긴다.

    • 메모리 할당 및 해제를 할 필요가 없다.

    • 스택에 할당 된 메모리 범위를 벗어나면, 사라진다. (실제로는 사라지기 보다는 나중에 스택 메모리를 사용해야 한다고 하면 덮어쓴다)

    • 변수와 매개변수를 위해 필요한 크기는 컴파일 도중에 알 수 있다. -> 런타임에는 스택 메모리 크기를 판단할 필요가 없다!(힙에 비해 속도 향상)

  • 하지만 스택에 큰 개체를 많이 넣으면

    • stack overflow 가 발생한다.

    • 성능이 느려질 수 있다.

다음 코드에서 스택의 생성 과정을 살펴보자

  1. 스택에 Foo 가 할당된다.

  2. 스택에 AddVector 가 할당된다.

  3. AddVector 를 모두 사용하고, 스택 포인터를 Foo 로 이동시킨다.

힙은 무엇일까?

  • 전역 메모리 공간(큼, GB 단위) -> 운영체제가 제공하는 메모리 공간으로 다른 프로그램과 공유될 수도 있다.

  • 비어 있고, 연속적인 메모리 공간을 찾아야만 한다. -> 때문에, 느리다 ..

  • 프로그래머가 직접 할당, 해제를 해주어야 한다.

    • 그렇지 않으면 메모리 누수가 발생한다.

    • C++ 은 언매니지드 언어이다!

다음 코드에서 힙의 생성 과정을 살펴보자

  1. 스택에 Foo 가 할당된다.

  2. 스택에 PrintVectors 가 할당된다.

  3. 운영체제에 의해서 힙에 Vector 가 할당된다.

  4. 힙에 잡혀있던 Vector 가 회수된다.

  5. PrintVectors 를 모두 사용하고, 스택 포인터를 Foo 로 이동시킨다.

개체 배열 생성, 소멸

  • 다음과 같이 Java 와 C++ 에서 개체 배열을 만들 때 메모리 할당 방식이 다르다.

  • Java

    • 배열의 각 요소에는 Vector 의 레퍼런스(주소)를 저장할 수 있는, 공간이 할당된다.

    • 따로 객체를 생성하기 이전에는 null 값이 할당된다.

    • 초기화와 동시에 10개의 객체를 만드는 공간을 힙에 할당할 수 없다..

  • C++

    • C++ 은 직관적이다.

    • 레퍼런스를 넣을 공간을 만드는 것이 아닌, 객체의 값을 넣을 수 있는 공간이 할당된다.

    • 초기화와 동시에 10개의 객체를 만드는 공간을 힙에 할당할 수 있다!

  • 다음과 같이 Java 와 C++ 에서 개체 배열을 만들 때 메모리 소멸 방식이 다르다.

  • Java

    • 메모리 관리를 개발자가 아닌, GC 에서 해주기 때문에 객체의 사용이 끝났다면(null 로 초기화를 해주면 언젠가는 메모리가 회수 된다) GC 가 메모리를 회수해간다.

    • 하지만 메모리를 즉시 회수해가지 않기 때문에, realtime 서비스에는 적합하지 않다.

  • C++

    • delete 지시어를 통해서 반드시 메모리를 회수해주어야 한다.

    • 개체 배열의 메모리 회수 시 [] 를 반드시 넣어 주어야 한다. -> 넣지 않는다면, 배열 크기 만큼에 메모리를 회수하는 것이 아닌, 첫번째 포인터 공간만 회수하게된다.

멤버 변수 초기화

  • 다음과 같이 Java 와 C++ 에서 개체 멤버 변수를 초기화 할 때, 초기화 방식이 다르다.

  • Java

    • 멤버 변수를 초기화 할 수 있는, 메모리 공간을 가져온다. 이 때는 다른 프로그램에서 사용 했었던 메모리 공간일 수 있기 때문에, 가비지 값이 들어가 있다.

    • 그 후 정수의 경우 기본값인 0으로 초기화 해준다.

  • C++

    • 멤버 변수를 초기화 할 수 있는, 메모리 공간을 가져온다. 이 때는 다른 프로그램에서 사용 했었던 메모리 공간일 수 있기 때문에, 가비지 값이 들어가있다.

    • 자바와 달리, 기본값으로 초기화하는 것이 아닌, 가비지 값 그대로 가지고 있다. -> 순수하게 성능 때문이다!

new, delete 와 malloc, free 의 차이는 무엇인가?

  • new delete

    • 메모리 할당과 초기화를 동시에 진행할 수 있다. -> 생성자가 있기 때문이다.

    • 생성자와 소멸자를 호출한다.

    • 할당된 메모리의 크기 변경이 불가능하다.

  • malloc free

    • 메모리 할당과 초기화를 동시에 진행할 수 없다.

    • 생성자와 소멸자를 호출하지 않는다.

    • 할당된 메모리 크기가 변경이 가능하다.

생성자, 초기화 리스트

  • 생성자에서 대입, 초기화 리스트를 보기에는 같아 보이지만 큰 차이가 있다.

    • 대입 : 개체 생성 후 초기화를 한다.

    • 초기화 리스트 : 개체 생성과 동시에 초기화를 한다.

  • 오류를 범할 수 있는 예는 다음과 같다.

    • 상수(const)나 참조변수(&)는 생성과 동시에 초기화를 해주어야 하기 때문에, 대입의 형태로 사용하게 되면, 오류가 날 수밖에 없다!

생성자와 소멸자

기본 생성자, 컴파일러가 하는 일

  • 기본 생성자는 매개변수를 받지 않는다.

  • 클래스에 생성자가 없으면 컴파일러가 기본 생성자를 자동적으로 만들어 준다.

  • 이렇게 자동적으로 만들어진 생성자는

    • 멤버 변수를 초기화하지 않는다.

    • 하지만 모든 포함된 개체의 생성자를 호출 한다.

생성자 오버로딩(Overrding)

  • 매개 변수를 가지는 생성자로 다음과 같이 사용할 수 있다.

  • 생성자 오버로딩을 하는 순간에 기본 생성자는 컴파일러가 만들어내지 않는다.

소멸자

  • C++ 에 만 있는 기능이다. -> Java 는 GC 가 있기 때문에, 소멸자가 없다.

  • 동적 할당 된 객체는, delete 시 소멸자가 호출되고,

  • 스택에 할당 된 객체는, 객체가 사용 되지 않을 때 소멸자가 호출 된다.

  • 클래스 안에서 동적 메모리 할당을 하게 되면 어떻게 할까? (string 클래스를 구현해보자)

  • 아래 코드의 문제는 무엇일까? -> 클래스를 스택에 저장하게 되면, 객체가 사용 되지 않을 때 자동적으로 메모리가 반환 되는데, 이때 힙에 메모리가 반환 되지 않고 남아있게 된다. (메모리 누수) -> 때문에, 소멸자를 통해서 힙 메모리를 해제해 주어야 한다!

구조체(Struct) 와 클래스(class)

  • C++ 에서 구조체와 클래스는 대부분 비슷하다. 다른 차이점은 아래 하나 뿐이다.

  • 기본 접근 권한

    • struct 는 public

    • class 는 private

  • 컴퓨터는 이 둘을 구분할까? -> 컴퓨터는 이 둘을 구분하지 못한다..

  • 컴파일러는 이 둘을 구분할까? -> 기본 접근 권한이 다르다는 차이가 있기 때문에, 컴파일러는 이 둘을 구분해야 한다!

  • 주의할 점은 무엇일까?

    • C++ 에서는 구조체를 클래스처럼 쓸 수 있다.

      • 하지만 절대 그러지 말아라!

      • 구조체는 C 스타일로 사용하자

    • struct 는 순수하게 데이터뿐이어야 한다!

      • 사용자가 선언한 생성자나 소멸자 X

      • static 아닌 private / protected 멤버 변수 X

      • 메모리 카피가 가능함!

Last updated