C++ has a zillion pitfalls, this lists some of the worst.
- Never write a
virtual const method. Avoid const methods.
class Base
{
virtual bool IfLoaded( void ) const;
};
class Derived
{
virtual bool IfLoaded( void ); // OOPS! forgot const
};
void Func( const Base& obj ) // pitfall opens here
{
if ( obj.IfLoaded() ) // calls Base::IfLoaded() despite the Derived class
}
What happens is that Derived::IfLoaded() DOES NOT OVERRIDE the base method.
Rather, Derived::IfLoaded() BECOMES A DIFFERENT/DISTINCT METHOD!
The reason is that they are methods with different types (const vs. non-const),
so C++ treats them as two different/distinct methods, rather than one polymorphic method.
A programmer can too easily forget if a virtual method should be const or non-const.
Advice is to avoid any kind const method (except maybe in basic self-contained classes).
Reusing or abusing assignment operator=() in a copy constructor:
This pitfall exists with more complex classes whose members aren't fundamental types.
Assignment operators should free members before reassigning them.
If an operator=() that frees resources is called in a copy constructor,
it will try to free garbage. A solution is have separate Copy() and Free() methods.
class Class
{
public:
Class( const Class& src )
{
*this = src; // the temptation to write terse code leads to a pitfall
}
Class& operator=( const Class& src )
{
delete mObj; // free members
mObj = src.Obj; // reassign members
return *this;
}
private:
Class2* mObj;
};
Method overriding will fail if you forget to write virtual
by a method in base class or the function signatures differ.
Calling a virtual method from a base constructor.
Think about the order of construction: the derived object hasn't been constructed yet.
Default copy constructors or assignment operators may cause trouble.
Safegaurds writing a dummy default copy constructor as private and/or with assert(0).
A constructor with a single arg might be misinterpreted as a conversion operator.
Write explicit if conversion isn't desired.
Class( int );
int n;
Class obj = n; // converts an int to a Class obj !!
Temporary objects and reference args
void Byref( int& x )
{
...
x = y;
}
Byref( a + 2 ); // oops, result went nowhere into a temp
operator bool()
operator bool() is seductive for tersely testing if an object is valid:
class Data
{
public:
operator bool() const { return mValid; }
private:
string mData;
};
void Process( Data& data )
{
// Valid data?
if ( data )
{
}
}
Let's say two objects are valid but their values (members) differ.
if ( data0 == data1 ) return;
You'd think return won't happen. But it will.
This is what's compiled:
if ( bool(data0) == bool(data1) ) return; // true == true
The pitfall is implicit conversion.
The class doesn't define operator==().
But the compiler doesn't supply a default memberwise comparison
as you might assume.
Rather, the compiler implicity converts both operands to bools.
Because that's precisely what operator bool() is for.