어떻게 용기류를 설계합니까

12195 단어 거푸집용기.
설계 컨테이너 클래스
1. 설계 원칙
a. 무엇이 포함되어 있습니까?
즉 용기에 무엇을 넣는지, 포함 대상인가?한 대상을 포함하는 정확한 의미는 무엇입니까?
컨테이너는 원래 대상 자체가 아니라 그 안에 놓인 대상의 사본을 포함해야 한다.개체를 가리키는 포인터를 컨테이너에 넣을 수 있습니다.
b. 복제 컨테이너는 무엇을 의미합니까?
컨테이너를 템플릿이라고 하고 컨테이너 내의 객체 유형이 템플릿 매개 변수입니다.복제 용기도 용기에 포함된 대상을 복제해야 하나요?
Container c1;
Container c2(c1);
혹은
Container c2;
c2=c1;
c2를 c1로 복제하면 c1과 c2가 같은 밑바닥 대상을 가리키게 되고 c2에 대한 변화도 c1에 비친다.만약 우리가 정의한 복제가 c2의 값을 c1에 넣는 것을 의미한다면 c2의 변화는 c1에 영향을 주지 않을 것이다.
C/C++의 내장 집합은 두 가지 다른 방법을 실현했다. 복제는 이 두 가지 방법에 있어 의미가 각각 다르다.
구조체 실현치의 의미;복사가 끝난 후, 두 변수는 모두 이 값의 독립된 복사본을 가지고 있다.
수조는 인용의 의미를 실현한다. 복제가 끝난 후에 두 변수는 모두 같은 밑바닥 대상을 인용한다(효율이 높다).
인용 계수와 쓰기 복제 기술은 용기 복제 비용을 줄일 수 있다.
복제 컨테이너는 컨테이너에 저장된 값을 복제하는 것으로 정의됩니다.
c. 용기의 원소를 어떻게 얻습니까?
즉, 컨테이너에서 대상을 꺼낼 때 유형 T&의 대상을 얻어야 하는가, 아니면 유형 T&의 대상을 얻어야 하는가?
용기에 대상을 가져올 때 복사 작업이 가져오는 추가 비용은 용기에 대상을 삽입할 때의 복사 작업의 추가 비용보다 훨씬 크고 대상 자체가 특정한 집합일 때 더욱 두드러진다.
 
용기의 대상을 수정할 수 있는 것이 우리에게 매우 중요하다면 용기는 대상의 인용을 제공해야 한다. 그렇지 않으면 용기에 포함된 대상을 바꾸는 다른 방법을 제공해야 한다.
d. 읽기와 쓰기를 어떻게 구분합니까?
operator[]를 사용하여 읽을 수 있으며, 원소를 쓰기 위해 함수를 정의할 수 있습니다.그러나 단독으로 정의된 업데이트 함수는 용기를 포함하는 용기에 원소를 쓰는 데 쓸모가 없을 수도 있습니다.용기의 용기에 대한 가장 좋은 절충 방법은 인용을 허용하는 것이다.인용을 만든 후에만 사용할 수 있음을 알립니다.
e. 용기의 증가를 어떻게 처리합니까?
존재하지 않는 요소를 저장하고 존재하지 않는 요소를 꺼내는 것을 피해야 한다.
원소를 만들기 전에 이 원소에 접근하려고 할 때 이상을 던지거나 미리 만들어진 용기 원소를 표시할 수 있습니다. 예를 들어 부족한 구조 함수로 되돌아오는 값을 보여 줍니다.
어떻게 용기 속의 원소에 메모리를 분배합니까?
예를 들어 그룹의 끝에 요소를 추가하면 블록에 따라 용기의 크기를 늘릴 수 있고 새로운 메모리 공간은 한 번에 분배되어야 한다.그러나 새 블록 크기 정책을 적절하게 계산할 때 주의해야 한다.
메모리를 시스템에 돌려주는 것도 언제 중요합니까?
f. 컨테이너는 어떤 작업을 지원합니까?
예를 들어 용기에 용기를 포함할 수 있습니까?만약 용기 내부에서 원소를 복제하고 원소의 다른 용기를 복제한다면, 이 용기는 반드시 복제될 수 있어야 한다.
용기에 부족한 구조 함수가 없으면 용기 그룹을 만들 수 없습니다.
용기의 모든 원소를 순서대로 훑어보다.(교체기)
g. 용기 원소의 유형을 어떻게 구상합니까?
 
컨테이너는 T 유형의 객체를 복제, 할당 및 제거해야 합니다.용기의 용도에 따라 T가 갖춰야 할 조작을 결정한다.
h. 컨테이너 및 상속
기본 클래스 B와 파생 클래스 D가 있다고 가정하고 D 대상을 하나의 Container에 넣으면 어떤 일이 일어날까요?
예를 들면 다음과 같습니다.
Class Vehicle{};
Class Airplane:public Vehicle{};
컨테이너가 있다면 에어플랜을 하나 넣으려면 에어플랜의Vihicle 부분의 사본만 받을 수 있습니다.전체 에어플랜을 기억하려면 컨테이너를 사용해야 합니다.
Contain이Container에서 계승된다면
Vehicle v;
Container ca;
Container &vp =ca;
Vp.insert(v);이렇게 하면 컨테이너에 일반적인 Vehicle을 삽입할 수 있습니다.사실 우리는 결코 이러고 싶지 않다.
서로 다른 유형의 용기는 상속 관계가 존재하지 말아야 한다.Container과 Container은 완전히 다른 종류입니다.
2. 설계 인스턴스(배열과 유사한 클래스)
#ifndef   _ARRAY_H

#define   _ARRAY_H

#include <iostream>

using namespace std;

namespace Meditation

{

    template<class T> class Array

    {

    public:

       Array():data(0),sz(0){} //      ,  new T[size]

       Array(unsigned int size):sz(size),data(new T[size]) { }

        const T& operator[](unsigned int n)const

       {

           if(n >= sz || data == 0)

              throw "Array subscript out of range";

           return data[n];

       }

       T& operator[](unsigned int n)

       {

              if(n >= sz || data == 0)

              throw "Array subscript out of range";

           return data[n];

       }

       //                  

       operator const T*() const

       {

           return data;

       }

        operator  T*() 

       {

           return data;

       }

 

    private:

       T *data;

       unsigned int sz;

       Array(const Array &a);

       Array&operator=(const Array&);

       //       

    };

}

#endif


 
상류 특징: 1.복사 및 할당 금지
              2.new T[size]를 만들 수 있습니다.
              3.T*에서 const T*로 제공
결함: 요소를 포함하는 Array가 사라진 후에도 요소의 주소가 존재합니다
를 참고하십시오.예:
Void f()
{
Int *p
{
Array x(20);
P=&x[10]
}
Cout<<*p<}
Array 객체 x는 역할 영역을 초과하고 p는 해당 요소를 가리킵니다.
 
a. 컨테이너의 요소에 액세스
위의 용기는 사용자로 하여금 Array 내부를 가리키는 바늘을 쉽게 얻을 수 있게 한다. 설령 Array 자체가 존재하지 않는다 하더라도 이 바늘은 여전히 거기에 남아 있다.Array가 사용하는 메모리가 변경되면 사용자 오류가 발생할 수 있습니다.어떻게 지침의 표현 능력을 보존하는 동시에 이런 부족함을 피할 수 있습니까?
Array와 내부 공간을 식별하는 클래스를 정의합니다. 이 클래스는 아래 첨자와 해당하는 Array를 가리키는 바늘을 포함해야 합니다.이 유형의 대상의 행위는 지침과 유사하다.
template<class T> class Pointer

    {

    public:

       Pointer(Array<T>& a,unsigned int n=0):ap(&a),sub(0) { }

       Pointer():ap(0),sub(0) { }

       T operator*()const

       {

           if(ap == 0)

              throw "* of unbound Pointer";

           return (*ap)[sub];

       }

       void update(const T&t)

       {

           if (ap == 0)

           {

              throw "update of unbound Pointer";

           }

           (*ap)[sub] = t;

       }

       T operator[](unsigned int n) const

       {

           if(n >= sz)

           {

              throw "Array subscript out of range";

           }

           return data[n];

 

       }

    private:

       Array<T> *ap;

       unsigned int sub;

   };


 
위에operator[]가 아닌 업데이트를 사용하여 용기의 값을 업데이트하면 용기에 용기가 포함되지 않습니다.
질문
Array가 존재하지 않으면, 오류를 방지하는 중간 층을 추가할 뿐입니다. 만약에 Array가 존재하지 않는다면, 원소를 가리키는 빈 현수막Pointer가 존재할 수도 있습니다.포인터를 사용하는 것은 포인터를 사용하는 것과 마찬가지로 혼란을 초래할 수 있다.예:
Array* ap= new Array(10);
Pointer p(*ap,s);
Delete ap;
*p = 42;
Array를 삭제한 다음 이 요소에 값을 부여해 보십시오. 이런 오류를 어떻게 피할 수 있습니까?
만약 우리가 어떤 Array 대상을 가리키는 Pointer 대상이 존재한다면 이 Array 대상은 사라지지 않을 것이며 상황은 바뀌지 않을 것인가?
Array를 어떻게 디자인해서 Array를 삭제할 때 Array를 정말로 사라지지 않게 합니까?
Array 객체가 삭제된 후에도 데이터가 유지되도록 추가 중간 레이어를 도입하여 Array 객체가 데이터를 포함하지 않고 가리키도록 해야 합니다.
세 가지 클래스 정의: Array, Pointer, Arraydata.각 Array 객체는 하나의 Array를 가리킵니다데이터 대상.
이제 Array를 삭제할 수 있습니다. 각 Pointer 객체는 Array를 가리킵니다Array 객체가 아닌 데이터 객체
Array 삭제 시기데이터 대상?Array나 Pointer가 없으면 어떤 Array를 가리키는데이터 대상, 이 Array부터 삭제데이터 대상.
방법: 각 Array 의 객체 수를 추적합니다.데이터 대상에는 인용 계수가 포함되어 있습니다.이 카운터는 Array 를 만듭니다.데이터를 1로 설정하고 이 Array를 가리킬 때마다데이터의 Array 또는 Pointer가 생성될 때 1이 증가하고, 이를 가리키는 Array 또는 Pointer가 삭제될 때 1이 감소합니다.참조 수가 0이면 Array 제거데이터 대상 자체.
template<class T> class Array_data {

    friend class Array<T>;

    friend class Ptr_to_const<T>;

    friend class Pointer<T>;

    Array_data(unsigned size = 0): 

       sz(size), data(new T[size]), use(1) { }

    ~Array_data() { delete [] data; }

 

    const T& operator[](unsigned n) const 

    {

       if (n >= sz) 

           throw "Array subscript out of range";

       return data[n];

    }

    T& operator[](unsigned n) 

    {

       if (n >= sz) 

           throw "Array subscript out of range";

       return data[n];

    }

    

    void resize(unsigned);

    void copy(T*, unsigned);

    void grow(unsigned);

    void clone(const Array_data&, unsigned);

    //    

    Array_data(const Array_data&);  // not implemented

    Array_data& operator=(const Array_data&); // not implemented

 

    T* data;

    unsigned sz;

    int use;

};


 
Array 클래스에는 Array가 있어야 합니다.데이터*(T*가 아닌, Array*는 대부분의 작업을 해당하는 Array데이터 객체:
다음은 Array 를 가리키는 Pointer를 정의합니다.Array 객체가 아닌 데이터 객체
template<class T> class Array {

    friend class Ptr_to_const<T>;

    friend class Pointer<T>;

public:

    Array(unsigned size): 

       data(new Array_data<T>(size)) { }

    ~Array() 

    {

       if (--data->use == 0)

           delete data;

    }

    const T& operator[](unsigned n) const 

    {

       return (*data)[n];

    }

    T& operator[](unsigned n) 

    {

       return (*data)[n];

    }

 

    void resize(unsigned n)

    {

       data->resize(n);

    }

 

    void reserve(unsigned new_sz)

    {

       if (new_sz >= data->sz)

           data->grow(new_sz);

    }

 

    Array(const Array& a): data(new Array_data<T>(a.data->sz))

    {

       data->copy(a.data->data, a.data->sz);

    }

    Array& operator=(const Array& a)

    {

       if (this != &a)

           data->clone(*a.data, a.data->sz);

       return *this;

    }

private:

    Array_data<T>* data;

};


 
//Pointer가 const Array 요소를 가리키도록 Ptr 정의to_const
template<class T> class Ptr_to_const {

public:

    Ptr_to_const(const Array<T>& a, unsigned n = 0):

       ap(a.data),   

       sub(n) { ++ap->use; }

 

    Ptr_to_const(): ap(0), sub(0) { }

 

    Ptr_to_const(const Ptr_to_const<T>& p): 

       ap(p.ap), sub(p.sub) 

    {

       if (ap)

           ++ap->use;

    }

 

    ~Ptr_to_const() 

    {

       if (ap && --ap->use == 0)

           delete ap;

    }

 

    Ptr_to_const& operator=(const Ptr_to_const<T>& p) 

    {

       if (p.ap)

           ++p.ap->use;

       if (ap && --ap->use == 0)

           delete ap;

       ap = p.ap;

       sub = p.sub;

       return *this;

    }

 

    const T& operator*() const 

    {

       if (ap == 0) 

           throw "* of unbound Ptr_to_const";

       return (*ap)[sub];

    }

 

protected:

    Array_data<T>* ap;

    unsigned sub;

};

 

template<class T> class Pointer: public Ptr_to_const<T> {

public:

    Pointer(Array<T>& a, unsigned n = 0):

       Ptr_to_const<T>(a,n) { }

    T& operator*() const 

    {

       if (ap == 0) 

           throw "* of unbound Ptr_to_const";

       return (*ap)[sub];

    }

};

이제 컨테이너를 다음과 같이 안전하게 조작할 수 있습니다.
Array *ap =new Array(10);
Pointer p(*ap,5);
delete ap;
*p=42;
전체 코드는 다음과 같습니다.http://download.csdn.net/download/xiaoding133/6192957

좋은 웹페이지 즐겨찾기