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

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
&bBase::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
&bBase::f()Base::g()Base::h()

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

地址函数1函数2函数3函数4函数5函数6
&dBase::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
&dDerive::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
&dBase1::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
&dDerive::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则是正常调用基类的函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值