Effective C++ item 37: Never Redefine a Function's Inherited Default Parameter Value

Virtual functions are dynamically bound, but default parameter values are statically bound. This make redefining an inherited function’s default parameter a really bad idea. Let’s see an example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Shape {
public:
enum ShapeColor { Red, Green, Blue };
virtual void draw(ShapeColor color = Red) const = 0;
...
};
class Rectangle: public Shape {
public:
virtual void draw(ShapeColor color = Green) const;
...
};
class Circle: public Shape {
public:
virtual void draw(ShapeColor color) const;
...
};

The symptom of the problem is similar to the one described in item 36. It’s unpredictable behavior depend on how draw is called.

1
2
3
4
Shape *pc = new Circle;
Shape *pr = new Rectangle;
pc->draw(); // calls Circle::draw(Shape::Red)
pr->draw(); // calls Rectangle::draw(Shape::Red)!

pr-draw() calls the correct function through dynamic binding but uses the default parameter from base class due to static binding.

Someone may think that this rule says never redefine inherited default parameter, what if I redefine it but make them the same? Like following?

1
2
3
4
5
6
7
8
9
10
11
class Shape {
public:
enum ShapeColor { Red, Green, Blue };
virtual void draw(ShapeColor color = Red) const = 0;
...
};
class Rectangle: public Shape {
public:
virtual void draw(ShapeColor color = Red) const;
...
};

Yeah of course you can do that but you just deferred the problem to the future, what if someone change just one place instead of all? So the correct thing to do it never redefine it.

One way to prevent derived class redefining it is using NVI idiom mentioned in item 35

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Shape {
public:
enum ShapeColor { Red, Green, Blue };
void draw(ShapeColor color = Red) const
{
doDraw(color);
}
...
private:
virtual void doDraw(ShapeColor color) const = 0;
};
class Rectangle: public Shape {
public:
...
private:
virtual void doDraw(ShapeColor color) const;
...
};

Reference:
“Effective C++” Third Edition by Scott Meyers.