OOP는 능숙되지 않은 프로그램머에게 나쁜프로그램을 못하게 하는 것이다 #


OOP는 데이터와 그 데이터를 조작하는 오퍼레이터를 캡슐화 함으로서
은닉화를 통한 데이터 보호와 추상화를 통한 인터페이스 노출, 상속을 통한
코드 재활용으로 견고하고 융통성있는 프로그램을 만들기 위한 좋은 개념입니다.
그 구체화된 도구가 class 입니다.


최소 완전한 class를 만들어라 #

Effective C++에서는" 최소 완전한 class를 만들어라 " 라고 얘기 하고 있습니다.
이 얘기는 첨에 이야기한 나쁜프로그램을 못하게하는 것과 일맥 상통하는 내용입니다.
작은 클래스라도 최소 인터페이스라도 완전한 클래스를 구현하는 내용입니다.

그 내용에는 다음과 같은 것들이 있을것입니다.
  • 생성
  • 소멸
  • 복사및 대입
  • 상속


생성 #

디폴트 생성자는 클래스의 기본적인 동작을 하는 내용을 담은 생성자 입니다.
이것은 기본적인 객체의 생성을 도와주고 동적배열 생성과 같은 행동에도 쉽게 문제를 해결해 줍니다.
class Item
{
public:
   Item();  // 디폴트생성자 - 구현생략 
};
허나 id와 같은 값이 필수인 객체를 생성할때 디폴트 생성자를 허용한다면
모든 멤버함수에서 id의 유효성을 검사하는 코드가 난무하거나
혹은 없는 id를 참조하는 불상하는 낼수도 있을것입다.

이럴땐 불편함(?)을 감수해서라도 디폴트 생성자를 제거하는것이 낳을 것입니다.
class Person
{
public:
   Person(int nID) : nID_(nID) {}  // 디폴트 생성자 없음 
private:
   int nID_;
};
그리고 한개의 인수를 가지는 생성자는 암시적인 형변환이 되므로
만약 암시적인 형변환때문에 문제의 소지가 발생할 여지가 있다면
다음과같이 explicit 키워드를 이용해 암시적인 형변환을 막는 것이 좋습니다.
class Person
{
public:
   explicit Person(int nID) : nID_(nID) {}
private:
   int nID_;
};

Person p;
p = 78; // explicit은 이 행동을 막아줍니다. 

만약 Factory Method 같은 패턴을 사용하기위해
정상적인 객체의 생성을 막을려면 디폴트 생성자를
private이나 protected로에 위치시키므로서 해결할수 있습니다.
class NoCreate
{

protected:
        NoCreate() {}
};


소멸 #

생성자에서 혹은 멤버함수에서 생성한 리소스는
항상 소멸자에서 가비지 콜렉션을 해주어야합니다.


복사및 대입 #

복사와 대입은 일관된 정책을 사용합니다
복사생성자가 존재한다면 대입연산자도 만들고
복사생성자가 존재하지 않는다면 대입연산자도 만들지 않습니다.

이유는 객체의 일관성과 일반화된 인터페이스를 제공해 주기 위함입니다.
class Item
{
public:
        Item(const Item& t);        // 복사생성자 
        Item& operator(const Item& t); // 대입연산자 
};

Item::Item(const Item& t)
{
}

Item& Item::operator(const Item& t)
{
        // 재귀치환을 검사합니다. 
        // 재앙을 막아줍니다. 
        if (this == &t) return *this;

        reutrn this;
}

만약 복사와 대입이 필요없다면 다음과같이
객체의 복사도 대입을 막아줍니다.

class NoCopy
{
public:
        NoCopy() {}

private:
        // 두가지 수단으로 함수호출을 저지합니다. 
        // 첫번째는 private 로 선언하여 외부의 노출을 막습니다. 
        // - 컴파일러가 사용을 막아줍니다. 
        // 두번째는 구현을 하지 않습니다. - 링커가 사용을 막아줍니다. 
        NoCopy(const NoCopy& t);        // 복사생성자 
        NoCopy operator(const NoCopy& t); // 대입연산자 
};



상속 #

만약 기초클래스의 용도로 사용될것이라면 소멸자에
virtual 키워드를 추가 하십시요
class Interface
{
public:
        virtual void MemberFunction() = 0;        // 순수가상함수 
        virtual ~Interface() {}
};

기초클래스의 포인터나 참조로 상속된 객체를 핸들링 할때
상속된 클래스의 소멸자가 호출 안되는 재앙을 막을수 있습니다.

Effective C++에 의하면 상속을 막는다면 문서로서 표시하지 말고
문법적으로 상속을 맞는 방법을 택하라고 되어 있습니다.

class Base
{
private:
        Base() {}

public:
        ~Base() {}
};


class Drived : public Base        // private 생성자가 상속을 막아줍니다. 
{};

void main()
{
        Drived d;                // (x) 에러 입니다. 

}


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

Stroustrup - The real interview  (0) 2008.05.01
qsort vs sort  (0) 2008.05.01
RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01
상속되지 않는것  (0) 2008.05.01
STL  (0) 2008.05.01

+ Recent posts