绝不重新定义继承而来的缺省值参数
文章目录
一、问题引入
- 在C++中,只能继承两种函数:虚(virtual)函数和非虚(non-virtual)函数。
-
而重新定义一个继承而来的带有缺省参数值的虚(virtual)函数永远是错误的
- 虚(virtual)函数是动态绑定
- 缺省参数值是静态绑定
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;
...
};
以上代码有个问题,如果你用下面的调用方式:
Shape *ps;
Shape *pc = new Circle;
Shape *pr = new Rectangle;
pc->draw(Shape::Red); //Circle::draw(Shape::Red);
pr->draw(Shape::Red); //Rectangle::draw(Shape::Red);
pr->draw(); //Rectangle::(Shape::Red)!!!!
- 我们会发现,pr的动态类型是Rectangle*, 所以调用的是Rectangle的virtual函数,Rectangle::draw的缺省参数应该是GREEN
- 但是,由于pr的静态类型是Shape*,所以此调用的缺省参数值来自Shape而不是Rectangle。
- C++之所以这么做,是
考虑到运行时效率的问题。如果缺省参数值是动态绑定,编译器就必须在运行期为虚函数决定适当的缺省值
。这比目前实行的“在编译器决定”机制更慢更复杂。
二、结论
-
绝对不要重新定义一个继承而来的缺省参数值,这些参数值都是静态的,而虚函数却是动态的
。
#include <iostream>
using namespace std;
class A
{
public:
virtual void Print(int a = 999)
{
cout<<a<<endl;
}
};
class B : public A
{
public:
virtual void Print(int a = 666)
{
cout<<a<<endl;
}
};
void Test(A& a)
{
a.Print();
}
int main()
{
B b;
Test(b);
return 0;
}
- 这段代码的输出结果是999而非666,也就充分验证我们的结论