C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数
来源:互联网 发布:java可以在手机上编程 编辑:程序博客网 时间:2024/04/29 09:21
派生类可以继承基类中的非私有函数成员,当然也就可以继承其中非私有的被重载的函数。如下:
【参考代码】
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++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数
- C++中派生类重写基类重载函数
- 基类和派生类之间的同名函数,存在重载吗?
- 基类中声明为virtual ,派生类中的同名函数
- 基类中声明为virtual ,派生类中的同名函数
- 虚函数 与派生类屏蔽基类函数
- 关于如何在派生类的虚函数中调用被覆盖掉的同名基类的虚函数
- 派生类覆盖基类的重载的函数
- C++派生类为什么不能重载基类的函数
- C++派生类为什么不能重载基类的函数
- 基类成员函数重载后派生类的使用。
- 【C++】派生类构造函数
- C++派生类中定义基类的虚函数时需注意的事项
- 虚函数与派生类重载
- 派生类构造函数的一些问题
- c++中派生类的构造函数
- 基类和派生类之间的同名函数处理方式
- 基类和派生类非虚函数和成员变量的同名
- mysql数据库的备份、导入、导出命令,以及数据的导入、导出
- 1. 概述
- 异常: Exception starting filter struts2 java.lang.NullPointerException
- toj1805 Electrical Outlets
- 第12期状元简讯:当当布局卖家服务市场 开放平台10月上线
- C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数
- CentOS 6.3(64位)上配置 VNC
- 常见adb异常以及处理方法
- Linux 内核机制--阻塞与非阻塞机制及Poll/Select分析
- 最难恢复的两类数据及数据恢复注意事项
- 通过AJAX的JS、JQuery两种方式解析XML
- 利用Command创建执行SQL语句的模块
- [IDA] 分析for循环的汇编代码
- 通过虚函数表调用虚函数与通过虚函数表(绕过访问权限控制)