C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数
Posted IIcyZhao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数相关的知识,希望对你有一定的参考价值。
派生类可以继承基类中的非私有函数成员,当然也就可以继承其中非私有的被重载的函数。如下:
【参考代码】
class Base
public:
void print()
cout << "print() in Base." << endl;
void print(int a)
cout << "print(int a) in Base." << endl;
void print(string s)
cout << "print(string s) in Base." << endl;
;
class Derived : public Base ;
int main()
Derived d;
d.print();
d.print(10);
d.print("");
return 0;
【运行结果】
print() in Base.
print(int a) in Base.
print(string s) in Base.
现在,我们想要在派生类中重写其中的一个重载函数:
class Derived : public Base
public:
void print()
cout << "Rewrite print() in Derived." << endl;
;
这样是不是就可以了呢? 我们来运行一下:
【运行结果】
reload_test.cc: In function ‘int main()’:
reload_test.cc:39: error: no matching function for call to ‘Derived::print(int)’
reload_test.cc:21: note: candidates are: void Derived::print()
reload_test.cc:40: error: no matching function for call to ‘Derived::print(const char [1])’
reload_test.cc:21: note: candidates are: void Derived::print()
下面一段内容来自 C++ Primer:
理解 C++ 中继承层次的关键在于理解如何确定函数调用。确定函数调用遵循以下四个步骤:
1. 首先确定进行函数调用的对象、引用或指针的静态类型。
2. 在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关基类中找到该名字,则调用是错误的。
3. 一旦找到了该名字,就进行常规类型检查,查看如果给定找到的定义,该函数调用是否合法。
4. 假定函数调用合法,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成代码直接调用函数。
原来,C++中,每个类都记录着在该类中定义的函数名及类型信息,当发生函数调用时,编译器先按函数名查找,如果在该类中查不到与之匹配的函数名,则向其父类查找,依次向上递归,直至函数名匹配成功,然后进行参数类型等信息的匹配;或者查到最顶层仍未匹配到相应的函数名。
所以,当我们在派生类中没有重写重载函数之一的时候,在派生类中调用的重载函数是在其基类中查到的,因此,调用可以成功;然而,当我们仅重写了其中的一个重载函数时,在做函数名匹配时,在本类中就可以匹配到了,就不会向其父类查找了。而在派生类中,仅记录了这个被重写的函数的信息,当然也就没有另外两个重载函数的一些了,因此就导致了上述错误的出现了。 换句话说,派生类中的函数会将其父类中的同名函数屏蔽掉。
因此,如果派生类想通过自身类型使用的基类中重载版本,则派生类必须要么重定义所有重载版本,要么一个也不重定义。
那么,如果在派生类中需要且仅需要重写其中一个重载函数,必须得把其它重载函数都重定义吗?有没有简便的方法,仅重定义我们想要改变的那个,其它的还是从父类继承呢。答案是肯定的,有,而且还可以有不同的方式:
一、通过using在派生类中为父类函数成员提供声明:
前面知道,因为派生类重写的函数名屏蔽了父类中的同名函数,那么我们可以通过using来为父类函数提供声明;这样,派生类不用重定义所继承的每一个基类版本,它可以为重载成员提供 using声明。一个 using 声明只能指定一个名字,不能指定形参表,因此,为基类成员函数名称而作的 using 声明将该函数的所有重载实例加到派生类的作用域。将所有名字加入作用域之后,派生类只需要重定义本类型确实必须定义的那些函数,对其他版本可以使用继承的定义。
上面说了那么多,不知道说明白了没有,不过,看了下面的例子,你就会豁然开朗: so easy!
class Derived : public Base
public:
using Base::print;
void print()
cout << "print() in Derived." << endl;
;
仅仅需要加入 using Base::print; 问题便解决了:
【运行结果】
print() in Derived.
print(int a) in Base.
print(string s) in Base.
二、通过基类指针调用
在调用被屏蔽的重载函数时,可以不直接通过派生类对象调用,而是通过基类指针指向派生类对象,通过基类指针进行调用,这样就会直接在基类中进行查找函数名,从而可以匹配并进行类型匹配。
int main()
Derived d;
Base* bp = &d;
d.print();
bp->print(10);
bp->print("");
return 0;
【运行结果】
print() in Derived.
print(int a) in Base.
print(string s) in Base.
但是这样就有两种调用方式,看起来很不舒服,而且容易弄错。那么把在派生类中需要重载的那个版本相应地在基类中声明为vitual,从而可以实现动态绑定,就能统一的使用基类指针来调用了:
【参考代码】
class Base
public:
virtual void print()
cout << "print() in Base." << endl;
void print(int a)
cout << "print(int a) in Base." << endl;
void print(string s)
cout << "print(string s) in Base." << endl;
;
class Derived : public Base
public:
void print()
cout << "print() in Derived." << endl;
;
int main()
Derived d;
Base* bp = &d;
bp->print();
bp->print(10);
bp->print("");
return 0;
【运行结果】
print() in Derived.
print(int a) in Base.
print(string s) in Base.
IIcyZhao's Road
本文链接地址: http://blog.csdn.net/iicy266/article/details/11906697
以上是关于C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数的主要内容,如果未能解决你的问题,请参考以下文章