-
函数重载
-
函数名相同
- 参数列表(个数/类型/顺序)不同
- 相同作用域
-
函数重载不考虑返回值的不同
-
函数隐藏
-
作用域不同
- 函数名相同
-
参数和返回值不考虑
-
函数覆盖(虚函数)
-
作用域不同(父子类之间的继承关系)
- 函数名,参数列表(参数个数/顺序/类型),返回值,调用约定必须相同
- 有virtual关键字
看一个例子:
1 #include <stdlib.h>
2
3 #include <iostream>
4 #include <string>
5 using namespace std;
6
7 class CPerson {
8 public:
9 void speak() { cout << "speak" << endl; }
10 };
11
12 class CChinese : public CPerson {
13 public:
14 virtual void speak() { cout << "speak Chinese" << endl; }
15 };
16
17 int main(int argc, char const* argv[]) {
18
19 CPerson per;
20 int nPersonSize = sizeof(CPerson);
21 cout << nPersonSize << endl;
22
23 return 0;
24 }
CPerson类仅有一个非虚函数的speak方法时,获取CPerson的大小
nPersonSize = 1; //1字节为一个占位符
将CPerson的speak声明为virtual虚函数
virtual void speak() { cout << "speak" << endl; }
此时CPerson的大小:
nPersonSize = 4; //虽然没有成员变量,但是有virtual关键字,有4字节的虚表指针
二、虚表中虚函数的顺序:
1.子类继承了所有父类虚函数(公有)
2.父类的虚函数顺序决定了子类虚函数的顺序3.子类重写了父类的某虚函数,则会在子类自己的虚表中覆盖对应位置的函数4.子类未重写某虚函数,则直接继承父类的该虚函数5.子类自己的虚函数会出现在前面父类所有虚函数后面
三、虚函数的直接调用与间接调用
1、直接调用
根据函数名称,直接调用该函数(编译器在编译时候就确定了其跳转地址)
1)普通函数的调用
2)对象的普通成员函数的调用
3)对象的虚函数的调用
2、间接调用(虚调用,通过查虚表来调用)
虚函数,通过查找对象的虚表下标来调用函数的方法(在运行时期确定调用谁)
1)通过对象的指针调用虚函数
CChinese* pChs = &chs;
pChs->foo();
2)通过对象的引用调用虚函数
CChinese& pChs = &chs;
pChs->foo();
3)以上两情况下,若明确了类域范围,则为直接调用
pChs->CChinese::foo();
四、函数覆盖隐藏重载
看以下示例,判断main输出结果
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
virtual void Handle1(float x) { cout << "Base::Handle1(float)" << endl; }
void Handle2(float x) { cout << "Base::Handle2(float)" << endl; }
void Handle3(float x) { cout << "Base::Handle3(float)" << endl; }
};
class Derived : public Base {
public:
virtual void Handle1(float x) { cout << "Derived::Handle1(float)" << endl; }
void Handle2(int x) { cout << "Derived::Handle2(int)" << endl; }
void Handle3(float x) { cout << "Derived::Handle3(float)" << endl; }
void Handle3(double x) { cout << "Derived::Handle3(double)" << endl; }
};
int main(int argc, char const *argv[]) {
Derived DervObj; //定义了一个子类的对象
//把子类对象传递给了父类,得到父类指针,子类指针强转父类指针是安全的
Base *pBase = &DervObj;
Derived *pDerv = &DervObj; //得到子类指针
pBase->Handle1(3.14f);
pDerv->Handle1(3.14f);
pBase->Handle2(3.14f);
pDerv->Handle2(3.14f);
pBase->Handle3(3.14f);
pDerv->Handle3(3.14f);
pDerv->Handle3(3.14);
return 0;
}
分析以下:
* 子类的1与父类的handle1,作用域不同(父子继承关系) ,函数名参数返回值都相同,且为虚函数,故为函数覆盖
-
看父子的Handle2、3,作用域不同,函数名相同,参数不管,为函数隐藏
-
看子类的Handle3,作用域相同,函数名相同,参数不同,为函数重载
// 间接调用:查表(查找子类的虚表),子类对象有函数覆盖,调用子类的Handle1
pBase->Handle1(3.14f);
//间接调用:查表(查找子类的虚表),子类对象有函数覆盖,调用子类的Handle1
pDerv->Handle1(3.14f);
原文链接: https://www.cnblogs.com/y4247464/p/13819881.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/203965
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!