Author : Mumit Khan
Page : << Previous 4 Next >>
data_(data) { }
Derived1(const Derived1& d) : Base("derived1"), data_(d.data()) { }
virtual ~Derived1() { }
virtual Base* clone() const { return new Derived1(*this); }
virtual void identify(ostream& os) const;
int data() const { return data_; }
private:
int data_;
};
virtual void Derived1::identify(ostream& os) const {
os << "(" << typename() << " " << data() << ")";
}
//
// Second derived class.
//
class Derived2 : public Base {
public:
Derived2(int data) : Base("derived2"), data_(data) { }
Derived2(const Derived2& d) : Base("derived2"), data_(d.data()) { }
virtual ~Derived2() { }
virtual Base* clone() const { return new Derived2(*this); }
virtual void identify(ostream& os) const;
int data() const { return data_; }
private:
int data_;
};
virtual void Derived2::identify(ostream& os) const {
os << "(" << typename() << " " << data() << ")";
}
//
// now define the pointer wrapper.
//
class BaseWrapper {
public:
BaseWrapper(Base* base_ptr = 0) : base_ptr_(base_ptr) { }
BaseWrapper(const BaseWrapper& bw) {
base_ptr_ = bw() ? bw()->clone() : 0;
}
~BaseWrapper() { delete base_ptr_; }
const Base* operator()() const { return base_ptr_; }
Base* operator()() { return base_ptr_; }
BaseWrapper& operator= (const BaseWrapper& bw) {
delete base_ptr_;
base_ptr_ = bw()->clone();
}
private:
Base* base_ptr_;
};
bool operator== (const BaseWrapper& bw1, const BaseWrapper& w2) {
return false;
}
bool operator< (const BaseWrapper& bw1, const BaseWrapper& w2) {
return false;
}
//
// end of class defs.
//
// define static members.
int Base::count = 0;
int main(int, char*[]) {
list<BaseWrapper> list1;
list1.push_back(BaseWrapper(new Derived1(101)));
list1.push_back(BaseWrapper(new Derived2(201)));
list1.push_back(BaseWrapper(new Derived2(202)));
list1.push_back(BaseWrapper(new Derived1(102)));
list1.push_back(BaseWrapper(new Derived2(203)));
list<BaseWrapper>::const_iterator it = list1.begin();
for(; it != list1.end(); ++it) {
const BaseWrapper& bw = *it;
bw()->identify(cerr);
cerr << " ";
}
cerr << endl << endl;
return 0;
}
And here's the output:
(derived1 101) (derived2 201) (derived2 202) (derived1 102) (derived2 203)
Templated pointer wrapper that takes a pointer to the base class
The following example shows 2 classes derived from Base, derived1 and derived2 and a templated wrapper Wrapper<T>. The wrapper class assumes that the base class provides a virtual clone facility and does the memory management.
Note: After the new'd Base derivative is passed to the wrapper, it owns it and deletes it in the destructor.
#include <stl.h>
#include <string.h>
#include <iostream.h>
//
// abstract base class
//
class Base {
public:
const char* typename() const { return typename_; }
virtual Base* clone() const = 0;
virtual void identify(ostream& os) const = 0;
virtual ~Base();
public:
static int count;
protected:
Base(const char* typename);
Base(const Base& base);
private:
char* typename_;
};
Base::Base(const char* typename) {
const char* tname = (typename) ? typename : "unknown";
strcpy(typename_ = new char[strlen(tname) + 1], tname);
++count;
}
Base::Base(const Base& base) {
strcpy(
typename_ = new char[strlen(base.typename_) + 1], base.typename_
);
++count;
}
Base::~Base() {
delete[] typename_;
--count;
}
//
// First derived class.
//
class Derived1 : public Base {
public:
Derived1(int data) : Base("derived1"), data_(data) { }
Derived1(const Derived1& d) : Base("derived1"), data_(d.data()) { }
virtual ~Derived1() { }
virtual Base* clone() const { return new Derived1(*this); }
virtual void identify(ostream& os) const;
int data() const { return data_; }
private:
int data_;
};
virtual void Derived1::identify(ostream& os) const {
os << "(" << typename() << " " << data() << ")";
}
//
// Second derived class.
//
class Derived2 : public Base {
public:
Derived2(int data) : Base("derived2"), data_(data) { }
Derived2(const Derived2& d) : Base("derived2"), data_(d.data()) { }
virtual ~Derived2() { }
virtual Base* clone() const { return new Derived2(*this); }
virtual void identify(ostream& os) const;
int data() const { return data_; }
private:
int data_;
};
virtual void Derived2::identify(ostream& os) const {
os << "(" << typename() << " " << data() << ")";
}
//
// now define a templated pointer wrapper. The class must support the
// clone() method.
//
template <class T>
class PtrWrapper {
public:
PtrWrapper(T* t_ptr = 0) : t_ptr_(t_ptr) { }
PtrWrapper(const PtrWrapper<T>& w) {
t_ptr_ = w() ? w()->clone() : 0;
}
~PtrWrapper() { delete t_ptr_; }
const T* operator()() const { return t_ptr_; }
T* operator()() { return t_ptr_; }
PtrWrapper<T>& operator= (const PtrWrapper<T>& w) {
delete t_ptr_;
t_ptr_ = w()->clone();
return *this;
}
private:
T* t_ptr_;
};
template <class T>
bool operator== (const PtrWrapper<T>& w1, const PtrWrapper<T>& w2) {
return false;
}
template <class T>
bool operator< (const PtrWrapper<T>& w1, const PtrWrapper<T>& w2) {
return false;
}
//
// end of class defs.
//
// define static members.
int Base::count = 0;
int main(int, char*[]) {
list<PtrWrapper<Base> > list1;
list1.push_back(PtrWrapper<Base> (new Derived1(101)));
list1.push_back(PtrWrapper<Base> (new Derived2(201)));
list1.push_back(PtrWrapper<Base> (new Derived2(202)));
list1.push_back(PtrWrapper<Base> (new Derived1(102)));
list1.push_back(PtrWrapper<Base> (new Derived2(203)));
list<PtrWrapper<Base> >::const_iterator it = list1.begin();
for(; it != list1.end(); ++it) {
const PtrWrapper<Base>& w = *it;
w()->identify(cerr);
cerr << " ";
}
cerr << endl << endl;
return 0;
}
(derived1 101) (derived2 201) (derived2 202) (derived1 102) (derived2 203)
Checking for an item in a map
This is from a bug we found in our code a while back.
typedef Map<int, X*, less<int> > XMap;
XMap xmap;
//
// populate xmap will what-not.
//
const X* xx = xmap[5];
if (xx == 0) { // not in map.
do_something();
} else {
do_something_else();
}
looks pretty innocuous, but what really happens is that a new entry for xmap[5] is created and gets stuffed with a NULL pointer which causes amazing amount of headache 10,000 lines of code later. The right way of course (and documented in the fine manual) is the following:
typedef Map<int, X*, less<int> > XMap;
XMap xmap;
//
// populate xmap will what-not.
//
XMap::const_iterator it = xmap.find(5);
if (it == xmap.end()) { // not in map.
do_something();
} else {
do_something_else();
}
More on evils of char*: Phone-book example
Motto: Never use char* if you can help it! See the following buggy example:
#include <stl.h>
#include <iostream.h>
typedef map<char*, unsigned long, less<char*> > Phonebook;
static void print_phbook(ostream& os, const Phonebook& map_) {
for(Phonebook::const_iterator i = map_.begin(); i != map_.end(); ++i) {
os << "\t(" << (*i).first << " " << (*i).second << ") " << endl;
}
}
static void change_phno(
Phonebook& phbook, const char* name, unsigned long phno
) {
char buf[1024];
strcpy(buf, name);
phbook[(char*)buf] = phno;
};
int main(int, char*[]) {
Phonebook phbook;
phbook[(char*)"grumpy"] = 5551212;
phbook[(char*)"sleepy"] = 5552121;
phbook[(char*)"gandhi"] = 5554242;
cerr << "==> Initial phone book" << endl;
print_phbook(cerr, phbook);
cerr << endl;
change_phno(phbook, "grumpy", 9995152);
cerr << "==> Grumpy moved. The new number is 9995152" << endl;
print_phbook(cerr, phbook);
cerr << endl;
char buf[1024];
Page : << Previous 4 Next >>