上篇C++57个入门知识点_35 函数覆盖的概念1(函数覆盖条件:父子类继承关系、函数名&参数列表&返回值&调用约定必须相同、有virtual关键字;函数覆盖:类虚表中成员函数从继承自父类变为自己的)中介绍了函数覆盖的基础知识,本篇将对其进行补充。
总结:
1. 函数覆盖(虚函数)
- 作用域不同(父子类之间继承关系)
- 函数名,参数列表(参数个数、顺序、类型),返回值,调用约定(
_thiscall
)必须相同 - 有
virtual
关键字
2. 虚表大小的确定
- 由编译器在编译时确定的
- 在运行时内存中并没有个数的表示
- 并不是以
00
结尾
3. 虚表中虚函数的顺序
- 子类继承了所有的父类父类虚函数(公有),虚函数一般都为父类的
- 父类虚函数顺序决定了子类虚函数的顺序
- 子类重写了父类的某虚函数,则会在子类自己的虚表中覆盖相应的位置的函数
- 子类未重写某虚函数,则直接继承父类的该虚函数
- 子类自己的虚函数会出现在自己虚表中父类对应所定义的虚函数后面
1. 子类虚函数函数名/参数列表/返回值/调用约定不同时是否构成函数覆盖
其中函数覆盖条件中函数名&参数列表&返回值&调用约定必须相同,如果不一样可不可以构成覆盖?
以下代码中,在子类CChinese中定义了与父类CPerson同名的虚函数,但是参数列表中多了一个int n
#include <iostream>
class CPerson {
public:
virtual void speak() {
printf("Cperson Speak!");
}
};
class CChinese :public CPerson
{
public:
virtual void speak(int n) {
printf("CChinese Speak!");
}
};
int main(int argc, char* argv[])
{
//函数覆盖
CPerson per;
int nSize = sizeof(per);
CChinese chs;
return 0;
}
运行结果:由于子类的函数也是一个虚函数,子类的虚表中有两个虚函数,一个是继承自父类,一个是本身的函数重载
因此 只有函数名&参数列表&返回值&调用约定完全相同情况下,子类的函数就会在子类虚表相应的位置覆盖父类函数,如果不一样,编译器会认为是不同的函数,在虚表中增加一项,而不是覆盖
。
2. 虚表的大小确定
每个类对象有各自的虚表,虚表的大小:
- 由编译器在编译时确定的
- 在运行时,内存中并没有个数的表示(编译时已经确定,没有必要记录个数)
- 并不是以
00
结尾,结尾是内存随机分配的
3. 虚表中虚函数的顺序
- 子类继承了所有的父类父类虚函数(公有),虚函数一般都为父类的
- 父类虚函数顺序决定了子类虚函数的顺序
- 子类重写了父类的某虚函数,则会在子类自己的虚表中覆盖相应的位置的函数
- 子类未重写某虚函数,则直接继承父类的该虚函数
- 子类自己的虚函数会出现在自己虚表中父类对应所定义的虚函数后面
以下代码中,CChinese
类中的虚函数顺序与父类CPerson
中对应虚函数顺序相反,并且子类中新增了一个void joke()
虚函数
#include <iostream>
class CPerson {
public:
virtual void speak() {
printf("Cperson Speak!");
}
virtual void eat() {
printf("Cperson Eat!");
}
virtual void fly() {
printf("Cperson Fly!");
}
};
class CChinese :public CPerson
{
public:
virtual void fly() {
printf("Cperson Fly!");
}
virtual void eat() {
printf("Cperson Eat!");
}
virtual void speak() {
printf("CChinese Speak!");
}
virtual void joke() {
printf("CChinese Joke!");
}
};
int main(int argc, char* argv[])
{
//函数覆盖
CPerson per;
int nSize = sizeof(per);
CChinese chs;
return 0;
}
运行结果如下:父类虚函数顺序决定了子类虚函数的顺序,子类自己的虚函数会出现在自己虚表中父类对应所定义的虚函数后面
4.学习视频地址:C++57个入门知识点_36 函数覆盖的概念2