Effective C++ 之条款33避免遮掩继承而来的名称

    名称的遮掩可以分为变量的遮掩和函数的遮掩两类,本质上都是通过名字的查找方式导致的,当编译器查找一个名字的时候,他一旦找到一个相符的名字,他就不会再找下去了,所以核心是看它从哪个作用域先找,因为查找是分作用域的。

//例1:普通变量遮掩
int i = 3;  //global 变量

int main()
{
    int i = 4;  //local变量
    cout << i << endl; // 输出4
}

上面的代码可以看作是普通变量的遮掩,在cout中输出i的时候,它首先在局部变量范围内查找,找到之后就不往上面找了。

对于名称的遮掩,主要重点在于名称,而不在于变量是什么类型(double 可以遮掩 int)。

下面我们再看看类成员变量的遮掩

class Base
{
public:
	int x;

	Base(int _x) :x(_x) {};
};

class Derived :public Base
{

public:
	int x;

	Derived(int _x) :Base(_x), x(_x + 1) {};
	int getbase_x() { return Base::x; };
};


int main()
{

	Derived d(3);

	std::cout << d.x<< std::endl;  //输出结果为4
	std::cout << d.getbase_x() << std::endl;  //输出结果为3
	return 0;
}

    虽然基类与派生类当中都有成员变量x,但是他们是相互隔离的。我再派生类中调用d.x,编译器会优先在派生类中查找。这也就是基类与派生类之间的成员变量的遮掩。

   与变量遮掩类似,函数名的查找也是先从子类独有的作用域开始查找的,一旦找到,就不再继续找下去了。这里无论是普通函数,虚函数,还是纯虚函数,结果都是输出子类的函数调用。

  但有一种情况要注意:

  

class Base
{
public:
	int x;

	Base(int _x) :x(_x) {};

	void CommonFunction() { std::cout << "Base::CommonFunction()" << std::endl; }
	void virtual VirtualFunction() { std::cout << "Base::VirturalFunction()" << std::endl; }
	void virtual VirtualFunction(int x) { std::cout << "Base::VirtualFunction() With Parms" << std::endl; }
	void virtual PureVirtualFunction() = 0;

};

class Derived :public Base
{

public:

	int x;
	Derived(int _x) :Base(_x), x(_x + 1) {};

	void CommonFunction() { std::cout << "Derived::CommonFunction()" << std::endl; }
	void virtual VirtualFunction() { std::cout << "Derived::VirturalFunction()" << std::endl; }
	void virtual VirtualFunction() { std::cout << "Derived::VirturalFunction()" << std::endl; }
	void virtual PureVirtualFunction() { std::cout << "Derived::PureVirtualFunction()" << std::endl; }

};


int main()
{

	Derived d(3);
	d.VirtualFunction(3);  //这里会报错,因为派生类同名成员函数没有参数列表,他是不会去基类成员 
                             函数中寻找的。

	//d.CommonFunction();	
	//d.PureVirtualFunction();

	return 0;
}

     很多人都会认为输出的是Base::VirtualFunction() With Parms,实际上这段代码却是编译不过的。因为编译器在查找名字时,并没有“为重载而走的很远”,C++的确是支持重载的,编译器在发现函数重载时,会去寻找相同函数名中最为匹配的一个函数(从形参个数,形参类型两个方面考虑,与返回值没有关系),如果大家的匹配程度都差不多,那么编译器会报歧义的错。

但以上法则成立的条件是这些函数位于相同的作用域中,而这里是不同的域!编译器先查找子类独有的域,一旦发现了完全相同的函数名,它就已经不再往父类中找了!在核查函数参数时,发现了没有带整型形参,所以直接报编译错了。

如果去掉子类的VirualFunction(),那么才会找到父类的VirtualFunction(int)。

提醒一下,千万不要被前面的Virtual关键字所误导,你可以试一个普通函数,结果是一样的,只要子类中有同名函数,不管形参是什么,编译器都不会再往父类作用域里面找了。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值