这样解决了第一个问题
发布时间:2025-06-24 20:07:22 作者:北方职教升学中心 阅读量:538
重点
- 虚函数表指针:每个包含虚函数的类都会有一个虚表指针,占用4字节,用于在对象中指向虚函数表,支持运行时的多态。
classPerson{public:
- 抽象类:包含纯虚函数的类,不能直接实例化,通常用作接口或基类。
func1
指向Base::func1
。classCar{public:virtualvoidDrive()final {}};classBenz:publicCar{public:virtualvoidDrive()override {cout <<"Benz"<<endl;}};
在这个代码中Drive函数被final修饰所以不能被重写/覆盖,同时在派生类中邪了override关键字用来检查函数时候被重写/覆盖,这样就会报错。
- 由于内存对齐,
_ch
后面会填充3字节,使得成员变量部分占用8字节。 🚀 2.1.2 虚函数
类的成员函数前面加上virtual修饰才能称为是虚函数,不是成员函数不能加virtual修饰
classPerson{public:virtualvoidBuyTicket(){cout<<"买票-全价"<<endl;}};
🚀 2.1.3 虚函数的重写/覆盖
虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数,我们这里说的完全相同是指虚函数的函数名,参数类型,返回值类型三个完全相同。
抽象类可以包含已实现的普通成员函数,但这不会改变其抽象类的特性。
📌 2 多态
的定义及实现
✨ 2.1 实现多态所需要的条件
多态是继承关系下的类对象,在调用同一函数的时候所产生的不同的行为
🚀 2.1.1 实现多态的两个重要条件
必须指针或者引用调用函数
要实现多态效果,第一必须是基类的指针或者引用,因为只有基类的指针和引用才能即指向派生类对象,又指向基类对象。
📌1 多态
✨ 1.1 多态
的概念
多态的概念:通俗来讲就是多种状态,多态编译分为运行时多态(动态绑定)和编译时多态(静态绑定)。我们可以发现 test
中并没有传入参数,但是我们忽略了作为一个成员函数总是有一个 this
指针,并且是父类的 this
指针,所以我们可以认为是 A
类型的 this
指针来调用的 func
函数。
虚函数表的优点
- 实现多态:虚函数表是C++实现运行时多态的核心,允许程序在运行时根据对象的实际类型选择函数。
然而多态不仅限于简单的继承和重写,它涉及虚函数表,动态绑定,菱形继承,虚继承等。 - 派生类继承该类时必须实现纯虚函数,否则派生类也会成为抽象类。
对于基类和派生类,编译器会为每个类单独生成虚函数表。
总内存占用:
示例:
classAnimal{public:virtualvoidsound()=0;voidsleep(){std::cout <<"Animal is sleeping"<<std::endl;}};classDog:publicAnimal{public:voidsound()override {std::cout <<"Woof!"<<std::endl;}};intmain(){Dog d;d.sound();d.sleep();return0;}
在该例子中,Animal
是一个抽象类,它定义了一个纯虚函数sound
。
特点: 示例:
classShape{public:virtualvoiddraw()=0;};classCircle:publicShape{public:voiddraw()override {std::cout <<"Drawing Circle"<<std::endl;}};classSquare:publicShape{public:voiddraw()override {std::cout <<"Drawing Square"<<std::endl;}};intmain(){Shape*s1 =newCircle();Shape*s2 =newSquare();s1->draw();s2->draw();deletes1;deletes2;return0;}
在上面的例子中,Shape
类是一个基类,它定义了一个纯虚函数draw
。
任何包含纯虚函数的类都无法直接实例化。虚表指针是对象级别的:每个对象实例都有自己的虚表指针,用于指向所属类的虚表。接下来我们来看 为什么继承的函数还是使用基类的缺省值。
🚀 2.1.5 override和final关键字
C++11提供了override,可以帮助⽤⼾检测是否重写。
func2
指向Base::func2
。目的:纯虚函数通常用于定义一个接口或规范,要求派生类必须提供该函数的具体实现。当一个类中包含虚函数时,编译器会自动为这个类生成一个虚函数表,用于存储类的虚函数地址。这个指针在对象创建时自动初始化,以指向该对象所属的类的虚函数表。✨总结
- 纯虚函数:只声明而没有定义的虚函数,用于要求派生类实现某些行为。
- 派生类可以继承抽象类并实现其纯虚函数,从而可以实例化派生类对象。Func(&st);Func(ps);Func(st);return0;}
🚀 2.1.4 多态场景的选择题
以下程序输出的结果是什么()
A: A->0 B: B->1 C: A->1 D: B->0 E: 编译报错
classA{public:virtualvoidfunc(intval =1){cout <<"A->"<<val <<endl;}virtualvoidtest(){func();}};classB:publicA{public:virtualvoidfunc(intval =1){cout <<"B->"<<val <<endl;}};intmain(){B*b =newB;b->test();return0;}
正确答案是 B : B->1
分析:
**接下来我们很定会有这样的疑问:**首先我们看到 b
对象是一个指向 B
类型的一个指针,但是 B
是派生类,为什么还会构成多态呢?构成多态的条件不是需要父类的指针吗?
**接下来我们带着疑问来解决上面的问题,**在 main
函数中 b
对象调用了 test
函数,并且通过 test
函数来调用 func
函数。

✨ 4.2 多态的原理
🚀 4.2.1 多态是如何实现的
classBase{public:virtualvoidfunc1(){cout <<"Base::func1"<<endl;}virtualvoidfunc2(){cout <<"Base::func2"<<endl;}voidfunc5(){cout <<"Base::func5"<<endl;}protected:inta =1;};classDerive:publicBase{public:virtualvoidfunc1(){cout <<"Derive::func1"<<endl;}virtualvoidfunc3(){cout <<"Derive::func1"<<endl;}};intmain(){