2011-02-05 14 views
2

私はStateZipCodeのリストとCityのリストを持ち、それぞれにZipCodeへのポインタを含むクラス階層を下の例のように持っています。ポインタを避けるためのC++デザインパターンのようなもの?

Cityを更新する(またはCityの新しいインスタンスを作成する)ことなく、ZipCodeを更新できるようにすることが目標です。

以下のC++コードはこの要件を満たしていますが、ポインタを使用しています。thisthatのために避けてください。 ポインタに依存しないようにこの[単純な]実装を再設計するにはどうすればよいですか?助けてくれてありがとう!

EDIT:ローポインタの代わりにboost::shared_ptrを使用するように、以下のコードを更新しました。 StateCity、およびZipCodeは例の名前に過ぎず、実際のコードではCityと同等のものが使用できるため、選択肢が不適切です(「A」、「B」、「C」を選ぶことができました) ZipCode秒を共有する。

#include <iostream> 
#include <vector> 
#include <boost/shared_ptr.hpp> 

using namespace std; 

/** 
* Zone Improvement Plan (ZIP) code 
*/ 
class ZipCode { 
public: 
    ZipCode() : code_(0), plus4_(0) {} 
    ZipCode(int code, int plus4 = 0) : code_(code), plus4_(plus4) {} 
    virtual ~ZipCode() {}; 

    int code() const { return code_; } 
    int plus4() const { return plus4_; } 
    void set_code(int code) { code_ = code; } 
    void set_plus4(int plus4) { plus4_ = plus4; } 

private: 
    int code_; 
    int plus4_; 
}; 

typedef boost::shared_ptr<ZipCode> ZipPtr; 

/** 
* City points to one or more zip codes 
*/ 
class City { 
public: 
    const vector<ZipPtr>& zip() const { return zip_; } 
    void add_zip_ptr(const ZipPtr x) { if (x != NULL) zip_.push_back(x); } 

private: 
    // TODO: this vector should be a hash set 
    vector<ZipPtr> zip_; 
}; 

/** 
* State contains cities, each of which has pointers to 
* zip codes within the state. 
*/ 
class State { 
public: 
    const vector<City>& city() const { return city_; } 
    const vector<ZipPtr>& zip() const { return zip_; } 

    const ZipPtr zip_of(int code) const { 
     for (size_t i = 0; i < zip_.size(); i++) { 
      if (zip_[i]->code() == code) { 
       return zip_[i]; 
      } 
     } 
     return ZipPtr(); 
    } 

    void add_city(const City& x) { city_.push_back(x); } 
    void add_zip(int code) { zip_.push_back(ZipPtr(new ZipCode(code))); } 

private: 
    // TODO: these vectors should be hash sets 
    vector<City> city_; 
    vector<ZipPtr> zip_; 
}; 

int main() { 
    State texas; 
    City dallas, houston; 

    // create state ZIPs 
    texas.add_zip(75380); 
    texas.add_zip(75381); 
    texas.add_zip(77219); 
    texas.add_zip(77220); 

    // point city ZIPs to the ones we just created 
    dallas.add_zip_ptr(texas.zip_of(75380)); 
    dallas.add_zip_ptr(texas.zip_of(75381)); 
    houston.add_zip_ptr(texas.zip_of(77219)); 
    houston.add_zip_ptr(texas.zip_of(77220)); 

    // print all ZIPs 
    cout << "ZIPs in Texas: " << endl; 
    const vector<ZipPtr>& zips = texas.zip(); 
    for (size_t i = 0; i < zips.size(); i++) { 
     cout << " " << zips[i]->code() << endl; 
    } 
    cout << "ZIPs in Dallas, Texas: " << endl; 
    const vector<ZipPtr> zip_ptrs1 = dallas.zip(); 
    for (size_t i = 0; i < zip_ptrs1.size(); i++) { 
     cout << " " << zip_ptrs1[i]->code() << endl; 
    } 
    cout << "ZIPs in Houston, Texas: " << endl; 
    const vector<ZipPtr> zip_ptrs2 = houston.zip(); 
    for (size_t i = 0; i < zip_ptrs2.size(); i++) { 
     cout << " " << zip_ptrs2[i]->code() << endl; 
    } 

    // change a state ZIP... 
    cout << "Changing Houston's ZIP 77220..." << endl; 
    ZipPtr z = texas.zip_of(77220); 
    if (z != NULL) z->set_code(88888); 

    // ...and show the ZIPs of the affected city 
    cout << "ZIPs in Houston, Texas: " << endl; 
    const vector<ZipPtr> zip_ptrs3 = houston.zip(); 
    for (size_t i = 0; i < zip_ptrs3.size(); i++) { 
     cout << " " << zip_ptrs3[i]->code() << endl; 
    } 

    return 0; 
} 
+1

あなたはC++を使用しています... – aqua

+1

書かれているように、コードが正しくありません:都市または郵便番号を州に追加すると、ベクター自体を再配分する必要があります。その時点で、既存の都市と郵便番号都市と郵便番号のオブジェクトがメモリ内の他の場所に移動したため、コードは無効になります。 –

+0

@James、そのバグを指摘してくれてありがとう。私は編集する必要があります –

答えて

0

あなたの郵便番号のオブジェクトを複製する場合を除き、あなたは(your first linkで説明)の使用のこのカテゴリーに入る:

バーインスタンスは、実際に、あなたのプログラムの他の部分で を管理されています Fooクラスはそれにアクセスできるのは である必要があります。

正当な使用のようです。

しかし、あなたの代わりにそれらZipCodesを配布するそのCitiesからState集計ZipCodesを(恒久的にベクトルがそのデータを再割り当てする必要がある場合の問題を回避するため)、またはメイクコピーオプションを検討する必要があります。

コピーは単にCityでポインタの使用を停止することを意味します。 ZipCodesを集約する代わりに、国家にZipCodesのリストを与える、あなたがCityZipCodeインスタンスのリストを与えるだろう、とzip_ofを呼び出すときに、あなたが都市を反復処理しそのZipCodeコレクションを反復処理することを意味します。

+0

ありがとう、ありがとう。実際、 'State'、' City'、 'ZipCode'は悪い例です(私の悪い)。私の実際のコードでは、 'City'に相当するものは' ZipCode'を共有できます。したがって、 'City'を' ZipCode'を集約するように変更すると、 'State'に' ZipCode'を複製することができます。 –

+1

@helloworld C++で物を共有する正しい方法は、ポインタまたは参照です。あなたはC++ 0x STLから 'std :: shared_ptr'か' std :: unique_ptr'を見ることができます。私は私の短い人生でそれを使用するのに十分なC++をやっていないが、C++ 0xがオプションでないならば、おそらくそれらのものと同等のものを持っているだろう。 – zneak

+0

boost :: shared_ptrは有望そうです...それに感謝します。私はちょうどそれを使用するかもしれない –

1

私は2つの1ような状況を参照してください:nの関係

  1. 状態:市== 1:nの

  2. 市:郵便番号 == 1:nの

それに基づいて、Stateには、

vector<ZipCode> zip_; 

は音ではありません。

私はポインタを必要としない

class State { 
    vector<City> cities_in_state_; 
}; 

class City { 
    vector<Zipcode> zips_in_city_; 
}; 

これを行う可能性があります。

+0

私は私の例であなたのコメントに同意します(そして、@zneakは実際に同じコメントをしました)。実際の会社独自のコードより理解しやすい実際の例を選んでいましたが(この場合、これらのクラス関係は意味をなさない)、私は明らかに失敗しました。 –