I have a class hierarchy as shown in the example below, where a State
contains a list of ZipCode
s and a list of City
s, each of which contain pointers to the ZipCode
s.
The goal is to be able to update the ZipCode
s without needing to update City
s (or to create new instances of City
).
The C++ code below meets this requirement, but it uses pointers, which I prefer to avoid because of this and that. How can I re-design this [naive] implementation so that it doesn't rely on pointers? Thanks for any help!
EDIT: Updated code below to use boost::shared_ptr
instead of raw pointers. Note that State
, City
, and ZipCode
are just example names, and they turned out to be poor choice names (I could've picked "A", "B", and "C") because the actual code allows the equivalent of City
to share 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;
}