派生类继承基类后会拥有基类的成员变量和成员函数,如果派生类中有和基类相同名称的成员函数和成员变量,那么派生类中相同名称的成员函数会把继承而来的成员函数“遮盖”掉。下面给出实例来进行分析。
class Base_A
{
public:
Base_A():element(0) {}
virtual ~Base_A() {}
void print(int a) { cout << a << endl; }
void print(float a) { cout << a << endl; }
private:
int element;
};
class Derived_B :public Base_A
{
public:
Derived_B():elem_B(1) {}
~Derived_B() {}
void print(const string& str) { cout << str << endl; }
void print() { cout << elem_B << endl; }
private:
int elem_B;
};
int main()
{
Derived_B B;
const string str = "基类函数给遮盖了!";
int a = 10;
float b = 12.0;
B.print(a);//编译无法通过,因为基类的同名函数被派生类遮盖了
B.print(b);//编译无法通过,同样是基类的同名函数被派生类遮盖了
B.print(str);
}
实际上,派生类的作用域被嵌套在基类的作用域内,如下图。
当派生类调用print()函数时,编译器的做法是从派生类的作用域到基类的作用域最后到全局中去寻找print()函数。所以开始的时候,编译器在派生类中寻找,看看有没有print(int )函数可以调用,发现没有。然后编译器只能继续往下寻找,看看派生类中有没有print(int)函数。实际上是有这个函数的,但是编译器看不见,因为被派生类的同名函数“遮盖”了。于是,编译器继续往全局作用域去找,还是没有找到。最后导致编译器报错。
需要强调的是:无论同名的函数是pure-virtual,virtual,还是non-virtual,编译器是一视同仁的。只要函数的名称是相同的,都会被派生类的同名函数所“遮盖”。
那有什么解决办法呢?既想要继承基类,并使用基类的部分成员函数,不想同名的函数被覆盖掉,那就使用using声明。在上面的代码中,在Derived_B的public后面加上:using Base_A::print ; 就可以轻松使用基类的同名函数了。
另一个方法是:在Derived_B中声明的函数,并调用Base_A中的函数,代码如下:
class Derived_B :public Base_A
{
public:
Derived_B():elem_B(1) {}
~Derived_B() {}
using Base_A::print;
void print(const string& str) { cout << str << endl; }
void print() { Base_A::print(elem_B); }//此处想调用Base_A的print函数,于是声明一个print函数,并在该函数中调用它。
private:
int elem_B;
};