Такая вещь, как шаблон проектирования C ++, чтобы избежать указателей? - PullRequest
2 голосов
/ 05 февраля 2011

У меня есть иерархия классов, как показано в примере ниже, где State содержит список ZipCode s и список City s, каждый из которых содержит указатели на ZipCode s.

Цель состоит в том, чтобы иметь возможность обновлять ZipCode s без необходимости обновлять City s (или создавать новые экземпляры City).

Код C ++ ниже отвечает этому требованию, но он использует указатели, которых я предпочитаю избегать из-за this и , что . Как мне перестроить эту [наивную] реализацию, чтобы она не зависела от указателей? Спасибо за любую помощь!

EDIT : обновлен код, приведенный ниже, чтобы использовать boost::shared_ptr вместо необработанных указателей. Обратите внимание, что State, City и ZipCode являются просто примерами имен, и они оказались плохими вариантами выбора (я мог бы выбрать «A», «B» и «C»), потому что фактическое Код позволяет эквивалентно City поделиться 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;
}

Ответы [ 2 ]

1 голос
/ 05 февраля 2011

Я вижу ситуацию как два отношения 1: n

  1. Штат: Город == 1: n

  2. Город: Почтовый индекс ==1: n

Исходя из этого, я думаю, что State, содержащий

vector<ZipCode> zip_;

, не является звуком.1019 *

class State {
    vector< City > cities_in_state_;
};

class City {
    vector< Zipcode > zips_in_city_;
};

Для этого не нужны указатели.

0 голосов
/ 05 февраля 2011

Если вы не хотите дублировать объекты ZipCode, вы попадаете в эту категорию использования (описано в ваша первая ссылка ):

Экземпляр Bar фактически управляется некоторымидругая часть вашей программы, в то время как класс Foo просто должен иметь к ней доступ.

Это выглядит как законное использование.

Однако вы можете рассмотреть копиюопция (чтобы навсегда избежать проблем, если вектор должен перераспределить свои данные) или сделать State агрегат ZipCodes из своих Cities вместо их распределения ZipCodes.

Копия просто подразумевает, что вы остановитеиспользуя указатели в City.Агрегация ZipCodes означает, что вместо предоставления State списка ZipCodes, вы бы дали City список ZipCode экземпляров, а при вызове zip_of вы будете выполнять итерации по городам и выполнять итерации по их ZipCode коллекция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...