在学习C++的继承与多态过程中我们接触到了隐藏与覆盖的概念,那么隐藏和覆盖分别做了些什么?
在C++的继承中我们知道派生类可以继承基类的成员变量和成员函数,那么当派生类继承基类的成员变量和成员函数时自己也有同名的成员变量和同名且同参数列表的成员函数时是如何处理的呢?
遇到这类情况C++的处理方式为隐藏和覆盖,下面就来介绍隐藏和覆盖。
隐藏
- 派生类将继承的基类的同名的成员变量和成员方法隐藏起来,通过派生类只能访问到自己的成员变量和成员方法。若想要访问基类的成员变量和成员方法需加上基类的作用域。隐藏以后的直接效果就是:无论在派生类的内部或者外部(通过派生类成员)访问该成员;全都是访问派生类的同名成员; 如果在派生类内部或者外部(通过派生类成员)访问同名的成员函数,则需要根据函数调用的规则来调用派生类的同名成员函数;
例如:
#include<iostream>
using namespace std;
class A
{
public:
void Show()
{
cout << "A::Show()" << endl;
}
public:
int ma = 10;
};
class B : public A
{
public:
void Show()
{
cout << "B::Show" << endl;
}
public:
int ma = 20;
};
int main()
{
B b;
B *pb = &b;
pb->Show();
cout << pb->ma << endl;
pb->A::Show();
cout << pb->A::ma << endl;
}
覆盖(重写)
- 覆盖往往与继承的类中有virtual修饰的函数有关。virtual修饰的函数为虚函数。而要构成覆盖就得满足基类中有virtual修饰的函数,而在派生类中有与基类中的虚函数同名且同参数列表的函数,那么派生类中的的该函数就会将基类中的函数覆盖,调用时无法调用基类中的函数。在子类中定义了一个与父类虚函数完全相同的函数,那么这个子类的函数就是重写了父类的虚函数,此时这个子类的函数就是虚函数,如果不显示的加上virtual修饰,编译器也会默认为虚函数。
- 覆盖(重写)达到的效果:
- 在子类中重写了父类的虚函数,那么子类对象调用该重写函数,调用到的是子类内部重写的虚函数,而并不是从父类继承下来的虚函数;(这其实就是动态多态的实现);
- 在子类中重写了父类的虚函数,如果用一个父类的指针(或引用)指向(或引用)子类对象,那么这个父类的指针或用引用调用该重写的虚函数,调用的是子类的虚函数;相反,如果用一个父类的指针(或引用)指向(或引用)父类的对象,那么这个父类的指针或用引用调用该重写的虚函数,调用的是父类的虚函数。
#include<iostream>
using namespace std;
class A
{
public:
virtual void Show()
{
cout << "A::Show()" << endl;
}
public:
int ma = 10;
};
class B : public A
{
public:
void Show()
{
cout << "B::Show" << endl;
}
public:
int ma = 20;
};
int main()
{
A *pa = NULL;
B *pb = NULL;
B b;
pa = &b;
pa->Show();
pb = &b;
pb->Show();
return 0;
}
基类的指针指向派生类对象,指向的是派生类中基类的部分,此时这个基类的指针调用在派生类中对基类中中虚函数重写的虚函数,调用的是派生类的虚函数。 相反,用一个基类的指针指向基类的对象,那么这个基类的指针调用该重写的虚函数,调用的是基类的虚函数,这是因为在基类中只有这一个函数。用派生类的指针调用该函数也调用的是派生类自己的函数。
补充:基类的指针能够指向派生类,这是因为派生类由自己的一部分和继承基类部分组成,基类的指针指向派生类其实是指向派生类中的基类部分。相反,派生类的指针无法指向基类。