One additional tip that I would offer is the following:
Use references when you can, pointers when you have to. If the object is guaranteed to exist, you should probably use a reference. If it is not, then you probably have to use a pointer.
One additional advantage is that references remove ambiguity on ownership. As soon as a maintenance programmer sees a pointer, they'll start to wonder if they should delete it.
Check this example out:
// Wrapper class using a reference because the wrapped object always exists
class Wrapper
{
public:
// If the wrapped is guaranteed to exist at creation, do it this way
Wrapper(Wrapped& wrapped):_wrapped(wrapped) { /* empty */ }
// put extra methods here.
int getWrappedValue() const { return _wrapped.getValue(); }
private:
Wrapped& _wrapped; // This object always exists and is valid
};
// Wrapper class written to support a possibly non-existent wrapped object.
class Wrapper
{
public:
Wrapper(Wrapped* wrapped = 0):_wrapped(wrapped) { /* empty */
void setWrappee(WRappee* wrapped) { _wrapped = wrapped; }
int getWrappedValue() const; // Not making inline -- more complex
private:
Wrapped* _wrapped; // Always check pointer before use
};
int Wrapper::getWrappedValue() const
{
if (_wrapped)
{
return _wrapped->getValue();
}
else
{
return -1; // NOTE, this is a contrived example -- not getting into exceptions
}
}