C++中的virtual函数(虚函数)

本文深入探讨了C++中虚函数的概念,通过实例演示了如何使用虚函数实现多态性,解释了虚函数与静态绑定的区别,以及在类继承中重写函数的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上周的C++课中,我第一次接触到虚函数(virtual function)这个非常重要的概念

什么是virtual函数?

在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。

简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。

看一段百度百科中的代码:

#include<iostream>
using namespace std;
class A
{
    public:
        void print()
        {
            cout<<"This is A"<<endl;
        }
};
 
class B : public A
{
    public:
        void print()
        {
            cout<<"This is B"<<endl;
        }
};
 
int main()
{
    //为了在以后便于区分,我这段main()代码叫做main1
    A a;
    B b;
    a.print();
    b.print();
    return 0;
}

输出的结果分别是“This is A”、“This is B”。
通过class A和class B的print()这个接口,可以看出这两个class因个体的差异而采用了不同的策略,但这并不是多态性行为(使用的是不同类型的指针),没有用到虚函数的功能。
现在把main()处的代码改一改。

int main()
{
    //main2
    A a;
    B b;
    A *p1 = &a;
    A *p2 = &b;
    p1->print();
    p2->print();
    return 0;
}

这时的结果却是:
This is A
This is A
很明显这不是我们想要的结果,但由于指针类型为A,程序已自动进行了静态绑定,所以调用了A类中的函数,为了解决这个问题,这时我们就需要用到虚函数

class A
{
    public:
        virtual void print(){cout<<"This is A"<<endl;}
};
class B : public A
{
    public:
    void print(){cout<<"This is B"<<endl;}
};

这时A中的成员函数print()已经称为了虚函数,而只需要将基类定义为虚函数,其派生类中的同名同参函数也会自动变为虚函数,所以B中不需要再加上virtual关键字修饰
现在重新运行main2的代码,这样输出的结果就是This is A和This is B了。

因此,virtual函数就是来帮助我们在C++程序类的继承中,实现函数的重写(Override)
可类比java,重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

virtual函数与静态绑定

再看一段代码:

#include <iostream>
using  namespace std;

class Parent
{    
 public:
     
     char data[20];
     void Function1();    
     virtual void Function2();   // 这里声明Function2是虚函数
     
 }parent;
 
 void Parent::Function1()
 {
     printf("This is parent,function1\n");
 }
 
 void Parent::Function2()
 {
     printf("This is parent,function2\n");
 }
 
 class Child:public Parent
 {
     void Function1();
     void Function2();
     
 } child;
 
 void Child::Function1()
 {
     printf("This is child,function1\n");
 }
 
 void Child::Function2()
 
 {
     printf("This is child,function2\n");
 }
 
 int main(int argc, char* argv[])
 {
     Parent *p;       // 定义一个基类指针
     if(_getch()=='c')    // 如果输入一个小写字母c    
         p=&child;        // 指向继承类对象
     else    
         p=&parent;       // 否则指向基类对象
     p->Function1();     // 这里在编译时会直接给出Parent::Function1()的入口地址。    
     p->Function2();     // 注意这里,执行的是哪一个Function2?
     return 0;
    
 }

在实际执行过程中:
当输入小写字母c,得到结果

1 This is parent,function1
2 This is child,function2

第一行原因:p指针为Parent类型,在程序运行前已经与其function1函数进行静态绑定,所以就算p指向的是一个Child对象,还是会调用Parent类的成员函数
第二行原因:第二行中调用了子类的function2,完全是因为virtual 函数的功能,virtual实现了动态联编,它可以在运行时判断指针指向的对象,并自动调用相应的函数。

而当你输入一个非c的字符,其结果为

1 This is parent,function1
2 This is parent,function2

这向我们展示了,使用virtual函数可以使得程序只调用一个函数,却能根据不同情况实现不同的功能,这就是virual的用途所在。

参考文档:C++中的virtual

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值