隐藏一定是用大对象指针/引用(派生类)
一.隐藏的两类情况:
1.派生类中声明了一个与基类同名的函数但参数却不同,不管基类有无virtual
2.派生类中声明了一个与基类同型的函数,但基类该函数未修饰为virtual函数
(同型函数:同名同参)
注意:情况1不是覆盖,无virtual为静态编译
情况2不是重载,重载发生在同一个名字空间
两类情况的结果:会发生 子类隐藏父类,只能访问子类的该函数
二、WHY?
这涉及:名称的隐藏 与作用域有关
C++名称查找规则:先去local作用域内查找,如果找到就不再查找其他作用域
(1)例:情况1
class Base{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
};
class Derived : public Base{
public:
virtual void mf1();
void mf3();
void mf4();
};
由于以作用域为基础的"名称查找规则",因此基类所有名为mf1和mf3的函数都被派生类的mf1和mf3函数都遮掩掉了。从名称查找的观点来看:Base::mf1()和Base::mf3不再被派生类继承:
Derived d;
int x;
d.mf1(); // ok, 调用Derived::mf1;
d.mf1(x); // error,因为Derived::mf1遮掩了Base::mf1
d.mf2(); // ok,调用Base::mf2
d.mf3(); // ok, 调用Derived::mf3
d.mf3(x); // error,因为Derived::mf3遮掩了Base::mf3
这可以看出,即使基类和派生类的函数有不同的参数类型、不管函数是virtual还是non-virtual,都有名称隐藏问题
这些行为背后的基本理由是为了防止你在程序库或者应用框架内建立新的派生类时附带的从疏远的基类继承重载函数。
如何实现继承重载?
实际上如果你正在使用public继承而又不继承那些重载函数,就会违反基类和派生类的is-a关系,因此你会想要推翻C++对”继承而来的名称“的缺省隐藏问题。
你可以使用using声明达成目标:
class Base{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
};
class Derived : public Base{
public:
using Base::mf1;
using Base::mf3; // 让基类的mf1和mf3内的所有东西在派生类的作用于可见
virtual void mf1();
void mf3();
void mf4();
};
现在,继承机制恢复了:
Derived d;
int x;
d.mf1(); // ok, 调用Derived::mf1;
d.mf1(x); // ok, 调用Base::mf1
d.mf2(); // ok,调用Base::mf2
d.mf3(); // ok, 调用Derived::mf3
d.mf3(x); //ok, 调用Base::mf3
(2)例:情况2
#include <iostream>
using namespace std;
//隐藏第一种情况
class Base
{
public:
void f() //基类非virtual
{
cout << "基类f()" << endl;
}
};
class Derived : public Base
{
public:
void f()//派生类有一个同型函数f()
{
cout << "派生类f()" << endl;
}
};
int main()
{
Base* p = new Derived();
Derived* q = (Derived*)p;
q->f(); //输出:派生类f()
//调用Derived::f() 用派生类q指针访问,下隐藏上,Derived::f()隐藏Base::f()
}