【C++面试】虚函数和纯虚函数

简介: 因为写代码时不能在一开始就确定被调用的是基类的函数,还是哪个派生类的成员函数,所以C++通过虚函数实现多态,即在基类中用virtual声明,父类可以引用子类对象(如Human* phuman1 = new Men;父类类型指针phuman指向子类对象),子类成员函数可以重写父类方法(函数)。

小米二面

在牛客网上的C++面筋题。


1. 虚函数和纯虚函数的区别

因为写代码时不能在一开始就确定被调用的是基类的函数,还是哪个派生类的成员函数,所以C++通过虚函数实现多态,即在基类中用virtual声明,父类可以引用子类对象(如Human* phuman1 = new Men;父类类型指针phuman指向子类对象),子类成员函数可以重写父类方法(函数)。

虚函数的核心理念就是通过基类访问派生类定义的函数:如在父类中用virtual声明某成员函数为虚函数,父类指针既能调用父类,也能调用子类中的同名同参成员函数。如下代码:

Human* phuman = new Men();
//男人喜欢吃米饭,调用的是子类Men类的eat函数
puhuman -> eat();
//人类吃各种粮食,调用的是Human类的eat函数
phuman->Human::eat();
delete phamn;

当存在继承关系时,父类的析构函数应当是虚函数(即虚析构函数),将调用相应对象类型的析构函数,因此,如果指针指向的是子类对象,将调用子类的析构函数,然后自动调用基类的析构函数;

如果父类析构函数没设置为虚函数,则delete指向子类对象的父类指针时,不会执行子类的析构函数释放内存,造成内存泄漏。

定义一个函数为虚函数,不代表函数为不被实现的函数。定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。


image.png

定义一个函数为纯虚函数,才代表函数没有被实现。纯虚函数没有函数体,同时在基类声明时需要在函数原型后加上=0。如上所示:

在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。所以出现【抽象类】(含有纯虚函数的类)就规定不能实例化为对象。

纯虚函数是为了安全,因为避免任何需要明确但是因为不小心而导致的未知的结果,提醒子类去做应做的实现。

【纯虚函数的实现原理】

纯虚函数也一定是某个类的成员函数,含有纯虚函数的类叫做抽象类。在C++中,抽象类无法实例化对象。如果我们定义了Shape这样的类,那么,Shape类当中,因为有虚函数和纯虚函数,所以它一定有一个虚函数表,也就一定有一个虚函数表指针。在虚函数表当中,如果是纯虚函数,那么虚函数表中的函数指针值为0;如果是普通的虚函数,那就肯定是一个有意义的值。

image.png

一个虚函数的最简单的栗子:

#include <iostream>
using namespace std;
class A{
public:
    virtual void foo()
    {
        cout<<"A::foo() is called"<<endl;
    }
};
class B:public A
{
public:
    void foo()
    {
        cout<<"B::foo() is called"<<endl;
    }
};
int main(void)
{
    A *a = new B();
    a->foo();   // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
  system("pause");
    return 0;
}

image.png

2. 构造函数能不能是虚函数

不能。。C++在编译期间,就能确定你要创建的对象的具体类型,而这个具体类型包含了什么,继承了什么在编译期间也是明确的,即构建一个对象,必须知道具体的类型信息,构造什么也都是明确的,根本没必要存在虚构造函数。虚函数的存在是因为编译期间没法确定具体调用对象,才会有虚函数,虚函数表这么个东西。


解决方案:Bjarne建议用factory pattern,也就是为每一个要构建的类型再创建一个对应的factory,把问题放到factory的make方法中去解决。这也是C++中的通用解决方案。


相关文章
|
C++
C++一分钟之-虚函数与抽象类
【6月更文挑战第21天】在C++中,虚函数与抽象类是多态的基础,增进类间耦合与灵活性。虚函数实现动态绑定,抽象类定义不可实例化的接口。关键点包括:记得使用`virtual`,避免滥用虚函数,确保派生类实现纯虚函数。抽象类不能直接实例化,派生类必须实现所有纯虚函数。通过实例代码学习和实践,能更好地掌握这些概念以优化代码设计。
306 2
|
12月前
|
缓存 安全 编译器
C++面试周刊(3):面试不慌,这样回答指针与引用,青铜秒变王者
《C++面试冲刺周刊》第三期聚焦指针与引用的区别,从青铜到王者级别面试回答解析,助你21天系统备战,直击高频考点,提升实战能力,轻松应对大厂C++面试。
953 132
C++面试周刊(3):面试不慌,这样回答指针与引用,青铜秒变王者
|
存储 算法 编译器
C++面试题其一
C++文件编译与执行的四个阶段 预处理:处理#include、#define等预处理指令。 编译:将源码翻译为目标代码。 汇编:将目标代码转换为机器指令。 链接:将目标文件和库文件合并生成可执行文件。 STL中的vector的实现,是怎么扩容的? vector通过动态数组实现,当容量不足时,分配更大的内存(通常是原来的两倍),复制旧数据到新内存,并释放旧内存。
300 2
|
存储 程序员 编译器
C++面试题其二
extern "C" 用于告诉编译器按照C语言的链接方式处理代码,通常用于C++代码与C代码混合编程,以防止因名字修饰(name mangling)引起的链接错误。例如: extern "C" { void c_function(); } 通过这些问题的深入理解和解答,能够更好地掌握C++编程的核心概念和实际应用,为面试做好充分的准备。
277 1
|
存储 网络协议 编译器
【干货总结】Linux C/C++面试知识点
Linux C/C++基础与进阶知识点,不仅用于面试,平时开发也用得上!
1496 125
|
存储 编译器 C++
【c++】多态(多态的概念及实现、虚函数重写、纯虚函数和抽象类、虚函数表、多态的实现过程)
本文介绍了面向对象编程中的多态特性,涵盖其概念、实现条件及原理。多态指“一个接口,多种实现”,通过基类指针或引用来调用不同派生类的重写虚函数,实现运行时多态。文中详细解释了虚函数、虚函数表(vtable)、纯虚函数与抽象类的概念,并通过代码示例展示了多态的具体应用。此外,还讨论了动态绑定和静态绑定的区别,帮助读者深入理解多态机制。最后总结了多态在编程中的重要性和应用场景。 文章结构清晰,从基础到深入,适合初学者和有一定基础的开发者学习。如果你觉得内容有帮助,请点赞支持。 ❤❤❤
1725 1
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
382 4
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
420 3
|
编译器 C++ 索引
C++虚拟成员-虚函数
C++虚拟成员-虚函数
|
存储 算法 C语言
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
427 5

热门文章

最新文章