解读:绝不重新定义继承而来的默认缺省参数

“绝不重新定义继承而来的默认缺省参数这句话来自于”《EffectiveC++》条款37。下面我们以一段代码开始我们的旅程.

#include
#include
#include

class Shap{
public:
	 virtual void print(int a = 1)=0;
	
	int c;
};
class Circle:public Shap
{
public:

 virtual void print(int a = 2)
	{
		c = a;
	}
};

int main()
{
	Shap *C = new Circle;
	C->print(2);
	printf("%d",C->c);
}
上面代码中我们输出是什么呢??答案是2这个很确定但是如果是以缺省参数调用C->print()呢 ???答案是1。也就是说其默认参数是其基类的默认参数,也就是说默认参数是静态绑定。这绝不是我们想要的。这也就是《Effective C++》中所说的绝不要重新定义继承而来的默认缺省参数。但是如果我们就是想让其在不同状态下有不同的参数那该怎么办呢???只有自己放弃使用子类默认参数了。但是如果这样考虑到代码的维护性,只要基类改变那么继承自他的所有子类都改变了。
《Effective C++》的作者为我们提供了一个很好的方式称为NVI(non_virtual_interface非虚函数接口)不得不说这本书真的很经典。他是怎么做的呢???
其并没有为我们提供虚函数接口,而是一个非虚的接口。C++不太好的同学请特别注意下面的代码。

#include
#include
#include

class Shap{
public:
	void print(int a)
	{
		print1(a);
	}
	 virtual void print(int a = 1)=0;
	
	int c;
};
class Circle:public Shap
{
public:

 virtual void print1(int a = 2)
	{
		c = a;
	}
};

int main()
{
	Shap *C = new Circle;
	C->print(2);
	printf("%d",C->c);
	return 0;
}

上面代码中我们多了一个print,而将另外两个命名为print1,下面我们来解释一下:
我们通过C->print(2)的调用来为赋值。在print中调用print1来实现。那么print调用的是子类的print1还是基类的print2呢??
答案是子类,有些人可能说基类是纯虚没有实现不可能调用,那么我们实现基类的print1呢??结果还是子类。现在我们梳理一下。
我们通过基类指针指向子类对象,调用的是父类的函数(因为print为非虚函数,通过父类指针不可能访问子类的非虚函数,即使子类将print覆盖,而这又违反类EffectiveC++的36条:绝不重新定义继承来哦非虚函数)而在父类的函数内部又调用的是子类的虚函数。这就NVI接口的真实调用过程。绕吧

你可能感兴趣的:(C/C++每天积累一点点)