《Effective C++》37: 绝不重新定义继承而来的缺省的参数值

动态绑定(dynamically bound)又名前期绑定(early binding),静态绑定(statically bound)又名后期绑定(late binding)。


所谓静态绑定是指在程序编译过程中,把函数(方法或者过程)调用与响应调用所需的代码结合的过程称之为静态绑定。

 动态绑定是指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法 除了限制访问,

访问方式也决定哪个方法将被子类调用或哪个属性将被子类访问. 函数调用与函数本身的关联,

以及成员访问与变量内存地址间的关系,称为绑定.动态绑定则针对运行期产生的访问请求,只用到运行期的可用信息. 

在面向对象的代码中,动态绑定意味着决定哪个方法被调用或哪个属性被访问,将基于这个类本身而不基于访问范围.

                                                                —— 摘自网络

对象的静态类型(static  type)就是它在程序中被声明时所采用的类型。

对象的动态类型(dynamic type)就是指目前所指向的对象的类型。

例如,

class Base
{
	......
};
class Derive : public Base
{
	......
};


则有:
Base * p;

p 的静态类型就是Base* ,因为它被Base*声明。

p没有动态类型,因为它没有指向任何的对象。

Base pB = new Base;
Base pD = new Derive;

pD和pB的静态类型都是Base*

pD的动态类型是Derive*,而pB的动态类型是Base*,因为他们实际指向的类型分别是Derive对象和Base对象。


virtual函数是动态绑定而来的,意思是调用一个virtual函数时,究竟调用哪一份函数实现代码,

取决于发出调用的那个对象的动态类型(而不是它的静态类型)。

但是,缺省参数(default parameter value)却是静态绑定的,应用哪一种缺省参数只取决于它的静态类型。

例如:

#include <iostream>
#include <string>
using namespace std;

class Widget
{
public:
	virtual void SaySomething(string msg 
		= "I'm Widget's default parameter value.")
	{
		cout << "I'm in Widget." << endl;
		cout << msg << endl;
	}
};

class Label : public Widget
{
public:
	virtual void SaySomething(string msg
		= "I'm Label's default parameter value.")
	{
		cout << "I'm in Label." << endl;
		cout << msg << endl;
	}
};

int main()
{
	Label* label = new Label;
	//静态类型和动态类型都是Label*
	//缺省参数和虚函数都调用Label类的
	label->SaySomething();

	cout << endl;

	Widget* wl = new Label;
	//静态类型是Widget*,动态类型是Label*
	//缺省参数调用Widget类的,虚函数调用Label类的
	wl->SaySomething();

	cout << endl;

	Widget* widget = new Widget;
	//静态类型和动态类型都是Widget*
	//缺省参数和虚函数都调用Widget类的
	widget->SaySomething();

	return 0;
}

实现效果:


这就意味着“调用一个定义于派生类内的虚函数”的同时,却又有可能使用基类为它所指定的缺省参数值。

因此建议:绝不重新定义继承而来的缺省参数值。

但如果你试着遵循这条规则,并提供同样的缺省参数值给基类和子类,又会怎么样呢?

class Widget
{
public:
	virtual void SaySomething(string msg 
		= "I'm Widget's default parameter value.")
	{
		cout << "I'm in Widget." << endl;
		cout << msg << endl;
	}
};

class Label : public Widget
{
public:
	virtual void SaySomething(string msg
		= "I'm Widget's default parameter value.")
	{
		cout << "I'm in Label." << endl;
		cout << msg << endl;
	}
};

代码重复,带有相依性。如果基类改变了缺省参数,则要为所有的子类修改缺省参数值。《Effective C++》给出的修改方法是NVI手法。



全部评论

相关推荐

AFBUFYGRFHJLP:直接去美帝试试看全奖phd吧
点赞 评论 收藏
分享
牛客5655:其他公司的面试(事)吗
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务