[面试题]虚函数和纯虚函数

简介:

虚函数

C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。

       如果调用非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数。非虚函数总是在编译时根据调用该函数的对象,引用或指针的类型而确定。如果调用虚函数,则直到运行时才能确定调用哪个函数,运行的虚函数是引用所绑定或指针所指向的对象所属类型定义的版本。

虚函数必须是基类的非静态成员函数。虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。

class Person{
    public:
        //虚函数
        virtual void GetName(){
            cout<<"PersonName:xiaosi"<<endl;
        };
};
class Student:public Person{
    public:
        void GetName(){
            cout<<"StudentName:xiaosi"<<endl;
        };
};
int main(){
    //指针
    Person *person = new Student();
    //基类调用子类的函数
    person->GetName();//StudentName:xiaosi
}

这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。

函数只能借助于指针或者引用来达到多态的效果。


纯虚函数

纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”  virtualvoid GetName() =0

       在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。为了解决上述问题,将函数定义为纯虚函数,则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

       将函数定义为纯虚函数能够说明,该函数为后代类型提供了可以覆盖的接口,但是这个类中的函数绝不会调用。

       声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。必须在继承类中重新声明函数(不要后面的=0)否则该派生类也不能实例化,而且它们在抽象类中往往没有定义。

定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。

纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。

//抽象类
class Person{
    public:
        //纯虚函数
        virtual void GetName()=0;
};
class Student:public Person{
    public:
        Student(){
        };
        void GetName(){
            cout<<"StudentName:xiaosi"<<endl;
        };
};
int main(){
    Student student;
}

抽象类

抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。

抽象类的定义:  称带有纯虚函数的类为抽象类。

抽象类的作用:抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。

使用抽象类时注意:抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。抽象类是不能定义对象的。

总结

1、纯虚函数声明如下: virtual void Fun()=0; 纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。

2、虚函数声明如下:virtual void Fun();虚函数必须实现,如果不实现,编译器将报错。

3、对于虚函数来说,父类和子类都有各自的版本。由多态方式调用的时候动态绑定。

4、实现了纯虚函数的子类,该纯虚函数在子类中就变成了虚函数,子类的子类即孙子类可以覆盖该虚函数,由多态方式调用的时候动态绑定。

5、虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。

6、在有动态分配堆上内存的时候,析构函数必须是虚函数,但没有必要是纯虚的。

7、友元不是成员函数,只有成员函数才可以是虚拟的,因此友元不能是虚拟函数。但可以通过让友元函数调用虚拟成员函数来解决友元的虚拟问题。

8、析构函数应当是虚函数,将调用相应对象类型的析构函数,因此,如果指针指向的是子类对象,将调用子类的析构函数,然后自动调用基类的析构函数。

9、有纯虚函数的类是抽象类,不能生成对象,只能派生。他派生的类的纯虚函数没有被改写,那么,它的派生类还是个抽象类。定义纯虚函数就是为了让基类不可实例化。因为实例化这样的抽象数据结构本身并没有意义。



目录
相关文章
|
6月前
|
C++
面试题:基类的析构函数为何要声明为虚函数?
面试题:基类的析构函数为何要声明为虚函数?
38 0
|
6月前
|
编译器 C++
面试题:什么是虚函数?
面试题:什么是虚函数?
54 0
|
测试技术
软件测试面试题:请讲一讲析构函数和虚函数的用法和作用?
软件测试面试题:请讲一讲析构函数和虚函数的用法和作用?
93 0
|
存储 缓存 Java
【阿里面试】C++多态和虚函数
2.1 现在假设有一个编译好的C++程序,编译没有错误,但是运行时报错,报错如下:你正在调用一个纯虚函数(Pure virtual function call error),请问导致这个错误的原因可能是什么?
316 0
【阿里面试】C++多态和虚函数
|
安全 C++
【C++面试】虚函数和纯虚函数
因为写代码时不能在一开始就确定被调用的是基类的函数,还是哪个派生类的成员函数,所以C++通过虚函数实现多态,即在基类中用virtual声明,父类可以引用子类对象(如Human* phuman1 = new Men;父类类型指针phuman指向子类对象),子类成员函数可以重写父类方法(函数)。
186 0
【C++面试】虚函数和纯虚函数
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
2天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
15 4
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
59 2