原网址http://www.weixueyuan.net/view/6375.html
函数遮蔽同样要求构成继承关系,构成继承关系的两个类中具有相同函数名的函数,如果这两个函数不够成覆盖关系,则就构成了遮蔽关系。遮蔽理解起来很简单,只要派生类与基类中具有相同函数名(注意不是相同函数签名,只需要相同函数名就可以了)并且不构成覆盖关系即为遮蔽。
遮蔽可以分为两种情况,一种是非虚函数之间,另一种则是虚函数之间。我们通过程序示例来分别介绍这两种遮蔽情况。
例1:
- #include<iostream>
- using namespace std;
- class base
- {
- public :
- void vir1(){cout<<"base vir1"<<endl;}
- void vir2(){cout<<"base vir2"<<endl;}
- };
- class derived : public base
- {
- public:
- void vir1(){cout<<"derived vir1"<<endl;}
- void vir2(int){cout<<"derived vir2"<<endl;}
- };
- int main()
- {
- base * p;
- p = new derived;
- p->vir1();
- p->vir2();
- delete p;
- derived d;
- d.vir1();
- d.vir2(5);
- d.base::vir1();
- d.base::vir2();
- return 0;
- }
在本例中没有虚函数,base类和derived类构成继承关系,因为构成继承关系的两个类中有同名函数,因此构成了函数遮蔽。派生类中的vir1函数遮蔽了基类中的vir1函数,派生类中的vir2函数遮蔽了基类中的vir1函数。需要注意的是虽然派生类中的vir2函数和基类中的vir2函数的函数签名不同,但是只需要函数名相同就构成函数遮蔽。我们接着来分析一下主函数,主函数中我们先是定义了基类类型的指针,指针指向的是基类对象,然后通过指针调用函数vir1和vir2,这个时候因为并不构成多态,因此调用的还是基类的vir1和vir2函数。之后定义了一个派生类对象d,通过该对象调用vir1和vir2函数,因为派生类中的vir1和vir2遮蔽了基类中的vir1和vir2函数,因此直接调用的将会是派生类中的vir1和vir2函数。如果需要通过派生类对象调用被遮蔽的基类中的函数,则需要通过域解析操作符来处理,在本例的最后d.base::vir1();和d.base::vir2()就是这么做的。这个程序的最终运行结果如下:
base vir1
base vir2
derived vir1
derived vir2
base vir1
base vir2
如果构成继承关系的两个类中包含同名的虚函数,则情况非常复杂,当然要判断还是非常简单,还是那个原则:如果没有构成覆盖则为遮蔽。覆盖要求的是函数签名相同,而遮蔽只需要函数名相同。
例2:
- #include<iostream>
- using namespace std;
- class base
- {
- public :
- virtual void vir1(){cout<<"base vir1"<<endl;}
- virtual void vir2(){cout<<"base vir2"<<endl;}
- };
- class derived : public base
- {
- public:
- virtual void vir1(){cout<<"derived vir1"<<endl;}
- virtual void vir2(int){cout<<"derived vir2"<<endl;}
- };
- int main()
- {
- base * p;
- p = new derived;
- p->vir1();
- p->vir2();
- delete p;
- derived d;
- d.vir1();
- d.vir2(5);
- d.base::vir1();
- d.base::vir2();
- return 0;
- }
总结: virtual与继承相关,多注意与多态,重载,覆盖和遮蔽的关系