C++|C++ 派生类函数重载与虚函数继承详解
目录
- 一、作用域与名字查找
- 1.作用域的嵌套
- 2.在编译时进行名字查找
- 3.名字冲突与继承
- 4.通过作用域运算符来使用隐藏的成员
- 二、同名函数隐藏与虚函数覆盖
- 1.几种必须区分的情况
- 2.一个更复杂的例子
类的关系图:
文章图片
一、作用域与名字查找 1.作用域的嵌套 派生类的作用域嵌套在基类之内
Bulk_quote bulk;
cout<< bulk.isbn();
名字isbn解析过程:
- 因为我们是通过Bulk_quote的对象调用isbn的,所以首先在Bulk_quote中查找,这一步没有找到名字isbn。
- 因为 Bulk_quote是Disc_quote 的派生类,所以接下来在Disc_quote中查找,仍然找不到。
- 因为Disc_quote是Quote的派生类,所以接着查找Quote; 此时找到了名字isbn,所以我们使用的isbn最终被解析为Quote中的isbn。
//给Disc_quote添加一个成员,返回折扣政策
class Disc_quote : public Quote {
public :
std::pair
我们只能通过Disc_quote及其派生类对象来使用discount_policy。
Bulk_quote bulk;
Bulk_qoute *bulkP = &bulk;
//静态类型与动态类型一致
Quote *itemP = &bulk;
//静态类型为Quote,动态类型不一定
bulkP->discount_policy();
//正确:bulkP的类型是Bulk_quote*
itemP->discount_policy();
//错误:itemP的类型是Quote*
尽管在bulk中确实含有一个名为discount_policy的成员,但是该成员对于itemP却是不可见的。
itemP的类型是Quote的指针,意味着对discount_policy的搜索将从Quote开始。
显然Quote不包含名为discount_policy的成员,所以我们无法通过Quote的对象、引用或指针调用discount_policy。
3.名字冲突与继承 派生类可以重用基类中的名字,由于派生类的作用域嵌套在基类中,所以会隐藏基类的同名变量
派生类成员隐藏同名的基类成员
struct Base{
Base():mem(0){}
protected:
int mem;
};
struct Derived : Base{//struct默认public继承
Derived(int i) : mem(i){};
int get_mem() {return mem;
}
protected:
int mem;
};
get_mem
返回的是在Derived中的memDerived d(42);
cout<
4.通过作用域运算符来使用隐藏的成员
struct Derived : public Base{
int get_base_mem() {return Base::mem;
}
//...
};
d.get_base_mem();
//输出0
二、同名函数隐藏与虚函数覆盖 1.几种必须区分的情况
派生类函数形式 | 与基类同名函数的关系 | 形参列表 | 绑定方式 |
---|---|---|---|
非虚函数 | 隐藏基类同名函数 | 可相同可不同 | 静态绑定 |
虚函数 | 覆盖基类虚函数 | 必须相同 | 动态绑定 |
使用基类的引用或指针调用虚函数时,会发生动态绑定
- 当派生类有基类的同名虚函数且该函数不是虚函数时,无论两个同名函数的参数是否相同。
- 由于派生类的作用域嵌套在基类内部,所以都会隐藏同名的基类函数
- 由于不是虚函数,所以即使两函数参数相同,也不会发生动态绑定
//情况1举例
class A{
public :
//基类的print不是虚函数
void print() const
{cout<<"class A"<
- 当派生类有基类的同名函数且该函数是虚函数时
- 参数列表相同,实现覆盖基类虚函数,可以发生动态绑定
//情况2:参数列表相同时,虚函数被覆盖 class A{ public : //基类的print是虚函数 void print() const {cout<<"class A"<
- 参数列表不相同,相当于派生类定义了一个新函数,隐藏了基类虚函数,基类的虚函数没有被覆盖
class A{ public : //基类的print是虚函数 void print() const {cout<<"class A"<
- 参数列表相同,实现覆盖基类虚函数,可以发生动态绑定
//类的定义class Base{
public :
virtual int fcn();
};
class D1 : public Base{
public:
//隐藏基类的fcn,这个fcn不是虚函数
//D1继承了Base::fcn()虚函数的定义
int fcn(int);
//形参列表与Base中的fcn不一致
virtual void f2();
//定义一个新的虚函数,它在Base中不存在
};
class D2 : public D1{
public :
int fcn(int);
//是一个非虚函数,隐藏了D1::fcn(int)
int fcn();
//覆盖了虚函数Base::fcn()
void f2();
//覆盖了虚函数f2
};
//调用虚函数的例子
//fcn是Base中的虚函数
//D1直接继承Base的虚函数fcn
//D2重载了Base的fcn
Base bobj;
D1 d1obj;
D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1jobj, *bp3 = &d2obj;
bp1->fcn();
//虚调用:运行时执行Base::fcn
bp2->fcn();
//虚调用:运行时执行Base::fcn
bp3->fcn();
//虚调用:运行时执行D2::fcn//f2是D1中的虚函数
//Base中没有定义f2
//D2重载了D1的虚函数f2
D1 *d1p = &d1obj;
D2 *d2p = &d2obj;
bp2->f2();
//错误:Base对象中没有名为f2的成员
d1p->f2();
//虚调用:执行D1::f2()
d2p->f2();
//虚调用:执行D2::f2()
//调用非虚函数的例子
//fcn(int)是D1中的 非虚函数
//Base中没有定义fcn(int)
//D2中的fcn(int)隐藏了D1中的fcn(int)
Base *p1 = &d2obj;
//d2obj是D2类型的对象
D1*p2 = &d2obj;
D2*p3 = &d2obj;
p1->fcn(42);
//错误:Base中没有接受int的fcn
p2->fcn(42);
//静态绑定:调用D1::fcn(int)
p3->fcn(42);
//静态绑定:调用D2::fcn(int)
推荐阅读
- 技术交流|详解用OpenCV绘制各类几何图形
- 关于Java错误提示之找不到或无法加载主类的问题及正确处理方法
- 程序员|用Python快速实现一个垃圾分类APP|附带微信小程序
- 五邑大学校级蓝桥杯c语言试题,【智能制造学部】第十届“蓝桥杯”软件类校内选拔赛顺利举行...
- python|手把手教你掌握4类数据清洗操作
- Java|Java SE --- 内部类
- 深度学习校招面试总结|人工智能面试总结-分类与聚类
- 实验|python实现knn分类算法和贝叶斯分类算法(数据集为UCI Iris和UCI Bank Marketing)
- sklearn|UCI Iris数据集K近邻方法建模预测鸢花种类
- 数据挖掘分类算法--KNN