Skip to main content

Item 37: Never redefine a function's inherited default parameter value

Concept

Default parameter values are statically bound, even when the function they're attached to is virtual (dynamically bound). This means that if you override a virtual function and give it a different default parameter value, calling the function through a base class pointer or reference will use the base class's default value — even though the derived class's function body executes. This mismatch between static default binding and dynamic function binding leads to confusing and error-prone behavior.

Code Example

class Shape {
public:
enum Color { Red, Green, Blue };
virtual void draw(Color c = Red) const = 0;
virtual ~Shape() = default;
};

class Circle : public Shape {
public:
// BAD: redefining default parameter
void draw(Color c = Green) const override {
// If called via Shape*, default is Red (base class), not Green!
}
};

// The problem:
Shape* sp = new Circle;
sp->draw(); // Calls Circle::draw(Red) — not Green!
// Dynamic binding picks Circle::draw
// Static binding picks Shape's default: Red

Full source code

Things to Remember

  • Never redefine an inherited default parameter value, because default parameter values are statically bound, while virtual functions — the only functions you should be overriding — are dynamically bound.
  • Item 36 — Never redefine an inherited non-virtual function (static binding issue)
  • Item 35 — NVI idiom as a solution (base controls defaults via non-virtual wrapper)
  • Item 34 — Interface vs implementation inheritance