当前位置: 代码迷 >> 综合 >> 21-0001 牛客网_一道虚函数练习题
  详细解决方案

21-0001 牛客网_一道虚函数练习题

热度:58   发布时间:2023-11-24 01:58:08.0

C++中的虚函数

  • 1.题目
  • 2.虚函数
    • 2.0 无继承
    • 2.1 一般继承
      • 2.1.1 无虚函数覆盖
      • 2.1.2 有虚函数覆盖
    • 2.2 多重继承
      • 2.2.1 无虚函数覆盖
      • 2.2.2 有虚函数覆盖
  • 3.参考链接
  • 4.又一道虚函数题目

1.题目

先看一下源代码,如下:

#include <iostream>
using namespace std;class A
{
    
public:void virtual print(){
    cout << "A" << endl;}
};class B : public A
{
    
public:void virtual print(){
    cout << "B" << endl;}
};int main()
{
    A* pA = new A();//父类指针pA->print();//父类指针子类函数B* pB = (B*)pA;//强制类型转换pB->print();//子类指针父类函数delete pA, pB;//pA = new B();//父类指针声明子类对象pA->print();//父类指针pB = (B*)pA;//pB->print();//子类指针return 0;
}

程序的输出:

A
A
B
B

2.虚函数

以下出现的所有函数都是虚函数
虚函数表:类中有虚函数,该类实例出的对象会有一个虚函数表

2.0 无继承

类Base如下:

函数1 函数2 函数3
Base +f():void +g():void +h():void

对于实例 Base b; 的虚函数表如下:

地址 函数1 函数2 函数3
&b Base::f() Base::g() Base::h()

2.1 一般继承

2.1.1 无虚函数覆盖

函数1 函数2 函数3
父类Base +f():void +g():void +h():void
子类Derive +f1():void +g1():void +h1():void

对于 b=new Base(); 实例的虚函数表:不需要管b是谁的

地址 函数1 函数2 函数3
&b Base::f() Base::g() Base::h()

对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的

地址 函数1 函数2 函数3 函数4 函数5 函数6
&d Base::f() Base::g() Base::h() Derive::f1() Derive::g1() Derive::h1()

2.1.2 有虚函数覆盖

函数1 函数2 函数3
父类Base +f():void +g():void +h():void
子类Derive +f():void +g1():void +h1():void

对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的

地址 函数1 函数2 函数3 函数4 函数5
&d Derive::f() Base::g() Base::h() Derive::g1() Derive::h1()

如上所示:子类中的虚函数会覆盖父类的虚函数,并且在虚函数表中将原父类的位置覆盖掉。

2.2 多重继承

2.2.1 无虚函数覆盖

函数1 函数2 函数3
父类1Base1 +f():void +g():void +h():void
父类2Base2 +f():void +g():void +h():void
父类3Base3 +f():void +g():void +h():void
子类Derive +f1():void +g1():void

对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的

地址 函数1 函数2 函数3 函数4 函数5
&d Base1::f() Base1::g() Base1::h() Derive::f1() Derive::g1()
- Base2::f() Base2::g() Base2::h()
- Base3::f() Base3::g() Base3::h()

子类实例中的虚函数会按照原来的顺序,仅仅放置在第一个继承的链表的最后方,保证寻址时的唯一性。

2.2.2 有虚函数覆盖

函数1 函数2 函数3
父类1Base1 +f():void +g():void +h():void
父类2Base2 +f():void +g():void +h():void
父类3Base3 +f():void +g():void +h():void
子类Derive +f():void +g1():void

对于 d=new Derive(); 实例的虚函数表:不需要管d是谁的

地址 函数1 函数2 函数3 函数4
&d Derive::f() Base1::g() Base1::h() Derive::g1()
- Derive::f() Base2::g() Base2::h()
- Derive::f() Base3::g() Base3::h()

会把每一个父类中覆盖的虚函数都替换掉。

3.参考链接

1.C++虚函数详解(你肯定懂了)

4.又一道虚函数题目

代码如下:

#include <iostream>
using namespace std;
struct Base{
    int i;virtual int f(){
    cout<<"a";return 1;}virtual const Base &f() const{
    cout<<"b";return *this;//不知道翻坠这句是什么作用}int g(){
    cout<<"c";return 3;}
};
struct Derive:Base{
    int i;int f(){
    cout<<"d";return 4;}const Base &f() const{
    cout<<"e";return *this;}int f(int =0){
    cout<<"f";return 6;}virtual int g(){
    cout<<"g";return 7;}
};int main(){
    Derive d;const Derive d_const;Base b,*p=&d;const Base *p_const=&d_const;b.f();p->f();p->g();p_const->f();d_const.f();
}

所以说上面的代码应该输出什么呢?

adcee

解释:

  1. b.f(); 基类对象直接调用基类的f()函数,输出a;
  2. p->f(); 派生类对象赋给基类的指针,由于f()在基类中是虚函数,根据基类指针指向的对象进行调用,因此调用派生类的int f()输出d;
  3. p->g();基类中g()不是虚函数,调用基类的g();
  4. p_const->f();常对象,又由于基类中声明为虚,同理用派生类中的函数;
  5. 同理。

更为经典的解释:

  • 只有通过基类指针(或引用)间接指向派生类子类型时多态性才会起作用。
  • 派生类的指针只调用自己的函数!
  • 基类指针的函数调用,如果有virtual则根据多态性调用派生类的函数;
  • 如果没有virtual则是正常调用基类的函数。