C++ 像C++;设计模式以避免指针?

C++ 像C++;设计模式以避免指针?,c++,design-patterns,pointers,C++,Design Patterns,Pointers,我有一个如下例所示的类层次结构,State包含一个ZipCodes列表和一个Citys列表,每个列表都包含指向ZipCodes的指针 #include <iostream> #include <vector> #include <boost/shared_ptr.hpp> using namespace std; /** * Zone Improvement Plan (ZIP) code */ class ZipCode { public:

我有一个如下例所示的类层次结构,
State
包含一个
ZipCode
s列表和一个
City
s列表,每个列表都包含指向
ZipCode
s的指针

#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;
}
目标是能够更新
ZipCode
s,而无需更新
City
s(或创建
City
的新实例)

<>下面的C++代码符合这个要求,但是它使用指针,我宁愿避免,因为strong>如何重新设计这个[naive]实现,使其不依赖指针?感谢您的帮助

编辑:更新下面的代码以使用
boost::shared_ptr
而不是原始指针。请注意,
State
City
ZipCode
只是一些示例名称,它们都是糟糕的选择名称(我可以选择“A”、“B”和“C”),因为实际代码允许相当于
City
的人共享
ZipCode
s

#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;
}
#包括
#包括
#包括
使用名称空间std;
/**
*区域改进计划(邮政编码)
*/
类ZipCode{
公众:
ZipCode():代码_0,plus4_0{}
ZipCode(int-code,int-plus4=0):code(code),plus4(plus4){
虚拟~ZipCode(){};
int code()常量{返回代码}
int plus4()常量{返回plus4;}
无效集合_码(int码){code_u=code;}
空集_plus4(int plus4){plus4_=plus4;}
私人:
int代码u3;;
整数加4;
};
typedef boost::shared_ptr ZipPtr;
/**
*城市指向一个或多个邮政编码
*/
阶级城市{
公众:
常量向量&zip()常量{return zip}
void add_zip_ptr(const zip tr x){if(x!=NULL)zip_u.push_back(x)}
私人:
//TODO:此向量应为哈希集
矢量压缩编码;
};
/**
*州包含城市,每个城市都有指向城市的指针
*州内的邮政编码。
*/
阶级国家{
公众:
常量向量&city()常量{返回城市}
常量向量&zip()常量{return zip}
常量ZipPtr zip_of(整数代码)常量{
对于(大小i=0;icode()==code){
返回邮政编码[i];
}
}
返回ZipPtr();
}
void add_city(const city&x){city_.push_back(x)}
void add_zip(int code){zip_u.push_back(ziptr(new ZipCode(code));}
私人:
//TODO:这些向量应该是散列集
矢量城市;
矢量压缩编码;
};
int main(){
德克萨斯州;
休斯敦达拉斯市;
//创建状态拉链
德克萨斯州。增加邮政编码(75380);
德克萨斯州。增加邮政编码(75381);
德克萨斯州。增加邮政编码(77219);
德克萨斯州。增加邮政编码(77220);
//point city将拉链拉到我们刚刚创建的位置
达拉斯。增加(德克萨斯州,邮编:75380));
达拉斯,增加了(德克萨斯州,邮编75381));
休斯顿。增加(德克萨斯州,邮编:77219));
休斯顿,增加了(德克萨斯州,邮编:77220));
//打印所有拉链

cout除非您想复制ZipCode对象,否则您属于这类用法(如中所述):

Bar实例实际上是被管理的 通过你程序的其他部分, 而Foo类只需要 能够访问它

这似乎是合法的使用

但是,您可能需要考虑复制选项(如果向量必须重新分配其数据,以永久避免问题),或者从其<代码>城市< /代码>中生成<代码>状态>代码>聚合>代码> ZIPCOD/<代码>,而不是分发它们:代码> ZIPCOND/<代码> .<


该副本只是暗示您停止在
City
中使用指针。聚合
ZipCodes
意味着不给State一个
ZipCodes
列表,而是给
City
一个
ZipCode
实例列表,当调用
zip\u of
时,您将遍历城市并迭代t通过他们的
ZipCode
集合。

我将这种情况视为两种1:n关系

  • 州:城市==1:n

  • 城市:Zipcode ==1:n

  • 基于此,我认为
    状态
    包含

    vector<ZipCode> zip_;
    
    vector-zip;
    
    声音不好

    我可以

    class State {
        vector< City > cities_in_state_;
    };
    
    class City {
        vector< Zipcode > zips_in_city_;
    };
    
    类状态{
    向量<城市>处于城市状态的城市;
    };
    阶级城市{
    矢量zips\u在城市中;
    };
    

    这不需要指针。

    编写的代码不正确:当您将城市或邮政编码添加到州时,向量可能需要重新分配自身,此时指向现有城市和邮政编码的所有指针都将无效(因为城市和邮政编码对象将移到内存中的其他位置)@James,谢谢你指出这个bug。我必须编辑一下,因为你的主题是关于避免指针编程范例,这可能会引起你的兴趣:(我喜欢这个吸引人的名字。)我不认为它是完全全面的,但这只是一个开始:)好的,谢谢。实际上,
    城市
    ,和
    ZipCode
    是一个坏例子(我的坏例子)在我的实际代码中,等价于<代码>锡蒂>代码>共享代码> >代码> >代码>。如果我改变了代码>锡蒂<代码>聚合>代码> ZIPCOD/<代码> s,则可以在代码< >代码>状态>代码>中重复复制<代码>代码> <代码> s。@与C++共享的正确方法是指针或引用。 >或代码> STD::UNIQUYGPTR <代码>,从C++ 0xSTL到帮助。在短时间内,我没有足够的C++来使用它,但是如果C++没有选择,Boost可能也有同样的值。Boosi::SyrdYpPTR看起来很有前途…谢谢。我可能只是用ITI同意您对我的例子中的1:N的评论。(而且@zneak实际上也发表了同样的评论)。我试图选择一个比实际公司专有代码更容易理解的实际示例(在这种情况下,这些类关系是有意义的),但我显然失败了:-\