### 프로그래머 지원 블로그 ### http://iwoohaha.tistory.com 

프로그래머는 이렇게 산다
by 우하하 이글루스 피플



이글루 파인더
활용~!!
최근 등록된 덧글
감사합니다!!! ^^
by 우하하 at 12/03
축하드립니다!!!!
by 이상훈 at 12/02
네.. 이겁니다 ㅠ.ㅠ 염..
by 코즈 at 12/02
간만에 왔다가 좋은 소식..
by 영재 at 12/01
축하한다. 승우야. 사진..
by 김상형 at 12/01
사진 찍는 자세를 아는걸..
by 우하하 at 12/01
감사합니다~
by 우하하 at 12/01
카테고리
생활의흔적
프로그래밍
컴퓨팅환경
요즘읽는책
블로그활용
공개자료실
아갖고싶다
디카작품전
즐겨서찾기
해야할일들
해보고싶은
작성중인글(비공개)
우하하실록
가보고싶은
결혼이야기
웃어보자구
모바일생활
공연이야기
마이쭈니어
음악이야기
부자만들기
소프트웨어
개발기록지
최근 등록된 트랙백
chrome for mac
by 착각속의 (아가)고양이 ..
이통사가 스마트폰 수입..
by 아라의 글로벌 마인드 칼..
아이폰, 스마트폰 등이..
by 아라의 글로벌 마인드 칼..
국회의원의 점심식사는?
by 미래를 만드는 정치인 ..
태그
iPodTouch 영한사전 새로운기능 프로그래밍언어 프라임 아이팟OS버그인가 단어학습 정신좀차려라 앱스토어 두산동아 체크카드혜택 5개국어 KB체크카드 한영사전 방통위는 아이폰 깜빡이 네비바 꺼짐은어떨까 보카 M8200 디폴트속성 프로모션 컨버전스기기 voca 아이팟터치 기억력테스트 제발부탁이다 iPhone
이전블로그
2009년 12월
2009년 11월
2009년 10월
2009년 09월
more...
라이프로그
rss

skin by 봉팔
알지 못하는(가상적으로) 타입에 대한 컨테이너 #1
Accelerated C++에서 발췌(p.369~396)

타입 의존성이 존재하는 코드

다음 코드에서 사용된 Core는 여기를 참조.

vector students; //다형적 타입이 아닌 Core 객체를 담는다.
Core record; //Core 객체. Core로부터 파생된 타입이 아님.


record의 타입은 Core이고, students는 Core타입을 담는 vector라고 명시했으므로 타입 의존성이 매우 명백하다.

위 코드를 보면서 vector라고 정의했을 때, vector의 각 객체가 Core 객체이지, Core로부터 파생된 타입의 객체가 아니라는 것을 아는 것이 중요하다.

타입 의존성을 제거하기 위해서...

다음과 같이 포인터로 변경한다.

vector students; //객체가 아닌 포인터를 저장한다.
Core* record; //임시변수도 포인터여야 한다.


또한 기본 타입의 포인터를 통해 파생 타입의 객체를 소멸시킬 수 있어야 하는 경우라면, virtual 소멸자를 사용해야 한다.

포인터를 저장하는 방식의 문제점

1. 포인터를 직접 관리해야 하는 추가적인 부담이 있다.
2. 그로 인해 버그를 발생시킬만한 여지가 많다.
사용자들은 레코드를 읽을 때 공간을 할당하는 것을 잊지 말아야 하며, 더 이상 데이터가 필요없게 되었을 때 그 공간을 해제하는 것도 잊지 말아야 한다.
3. 내부 객체들에 접근하려면 항상 포인터를 역참조해야 하는 불편이 있다.

핸들 클래스

Grad는 Core로부터 파생된 클래스이다. Core에 대한 포인터를 사용하면, 그 포인터는 Core객체를 가리킬 수도 있고 Grad객체를 가리킬 수도 있기 때문에 포인터를 사용하는 방법을 선택하였다.
하지만 이 방법은 사용자들에게 오류의 위험이 다분한 여러 가지 요구사항을 부여한다는 것이 문제이다.
이러한 요구사항을 없애버릴 수는 없지만, Core에 대한 포인터를 캡슐화시킨, 새로운 클래스를 사용하면 사용자에게 안보이게 할 수는 있다.

class Student_info
{
public:
    //생성자들 및 복사 제어(copy control)
    Student_info() : cp(0) {}
    Student_info(std::istream& is) : cp(0) { read(is); }
    Student_info(const Student_info&);
    Student_info& operator=(const Student_info&);
    ~Student_info() { delete cp; }

    //연산들
    std::istream& read(std::istream&)
    {
        delete cp;//만약 있다면 이전 객체를 해제함.

        char ch;
        is >> ch; //레코드 타입을 얻음.

        if (ch == 'U')
        {
            cp = new Core(is);
        }
        else
        {
            cp = new Grad(is);
        }
        return is;
    }

    std::string name() const
    {
        if (cp) return cp->name();
        else throw std::runtime_error("uninitialized Student");
    }

    double grade() const
    {
        if (cp) return cp->grade();
        else throw std::runtime_error("uninitialized Student");
    }

private:
    Core* cp;
};


여기에서의 아이디어는 Student_info 객체로 Core나 Grad를 나타내도록 하는 것이다.
즉, 포인터처럼 동작하는 것이다. 하지만, 사용자들은 Student_info에 바인딩되는 내부 책체의 할당에 대해서는 신경쓸 필요가 없다.
지루하고 에러 위험이 있는 작업들은 클래스가 알아서 처리한다.
참조:p.374

핸들 객체 복사

Core 클래스와 Grad 클래스에 다음 코드를 추가.
class Core
{
    friend class Student_info;
protected:
    virtual Core* clone() const { return new Core(*this); }
    //나머지는 이전과 동일
};

class Grad
{
protected:
    Grad* clone() const { return new Grad(*this); }
    //나머지는 이전과 동일
};


Student_info 클래스에 다음 코드를 추가
    Student_info(const Student_info& s)
    {
        if (s.cp) cp = s.cp->clone();
    }

    Student_info& operator=(const Student_info& s)
    {
        if (&s != this)
        {
            delete cp;
            if (s.cp)
                cp = s.cp->clone();
            else
                cp = 0;
        }
        return *this;
    }


핸들 클래스 사용하기

int main()
{
    vector<Student_info> students;
    Student_info record;
    string::size_type maxlen = 0;

    //데이터를 읽고 저장한다.
    while (record.read(cin))
    {
        maxlen = max(maxlen, record.name().size());
        students.push_back(record);
    }

    //이름과 성적을 출력한다.
    for (vector<Student_info>::size_type i = 0; i != students.size(); ++i)
    {
        cout << students[i].name() << string(maxlen+1-students[i].name.size(), ' ');
        try 
        {
            double final_grade = students[i].grade();
            streamsize prec = cout.precision();
            cout << setprecision(3) << final_grade << setprecision(prec) << endl;
        }
        catch (domain_error e) {
            cout << e.what() << endl;
        }
    }

    return 0;
}


핸들 클래스의 템플릿 클래스화

template <class T>
class Handle
{
public:
    Handle() : p(0) {}
    Handle(const Handle& s) : p(0) { if (s.p) p = s.p->clone(); }
    Handle& operator=(const Handle& rhs)
    {
        if (&rhs != this)
        {
            delete p;
            p = rhs.p ? rhs.p->clone() : 0;
        }
        return *this;
    }
    ~Handle() { delete p; }
    Handle(T* t) : p(t) {}
    operator bool() const {return p;}
    T& operator*() const
    {
        if (p) return *p;
        throw runtime_error("unbound Handle");
    }
    T* operator->() const
    {
        if (p) return p;
        throw runtime_error("unbound Handle");
    }
};


이 블로그를 구독하시려면 이 버튼을 눌러주세요 ===>


by 우하하 | 2004/02/10 00:40 | 프로그래밍 | 트랙백 | 덧글(0) | ▲ Top
트랙백 주소 : http://woohaha.egloos.com/tb/272867
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글



◀ 이전 페이지 다음 페이지 ▶