首页 > 编程语言 >理解C++虚函数和虚表(vtbl)机制

理解C++虚函数和虚表(vtbl)机制

时间:2024-06-22 13:27:44浏览次数:14  
标签:调用 虚表 函数 show vtbl C++ 派生类 指针

引言

C++ 是一种强大且灵活的编程语言,它支持面向对象编程(OOP)的各种特性,其中虚函数(virtual function)是实现多态性(polymorphism)的关键机制。本文将深入探讨虚函数的原理、虚表(vtbl)的作用,以及这些特性在实际编程中的实现。通过理解这些概念,您将能够更好地掌握C++的多态性和面向对象编程。

虚函数的原理

虚函数是一种在基类中使用 virtual 关键字声明,并且可以在派生类中重写的函数。它允许通过基类指针或引用来调用派生类的函数实现,从而实现运行时多态。

虚函数的工作原理

当一个类包含虚函数时,编译器会为这个类生成一个虚函数表(vtbl),该表存储了指向虚函数实现的指针。每个包含虚函数的类都有一个独立的虚表。当一个对象创建时,它会包含一个指向虚表的指针(通常称为虚表指针或vptr)。通过这个指针,程序可以在运行时动态地决定调用哪个函数实现。

虚表(vtbl)的作用

虚表是类级别的结构,而不是对象级别的。这意味着每个包含虚函数的类都有一个共享的虚表,而不是每个对象都拥有自己的虚表。每个对象会有一个指向所属类的虚表的指针,这样在运行时可以通过该指针来调用正确的虚函数实现。

代码示例

以下是一个关于虚函数和虚表的简单示例,展示了它们的使用和工作原理。

#include <iostream>

// 基类
class Base {
public:
    virtual void show() {
        std::cout << "Base class show function" << std::endl;
    }

    virtual ~Base() = default; // 虚析构函数,以确保派生类对象被正确销毁
};

// 派生类
class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived class show function" << std::endl;
    }
};

int main() {
    Base* basePtr = new Derived(); // 基类指针指向派生类对象
    basePtr->show(); // 调用派生类的 show 函数

    delete basePtr; // 正确调用派生类的析构函数
    return 0;
}

代码解析

  1. 基类声明

    • Base 类声明了一个虚函数 show,并提供了默认实现。
    • 基类还声明了一个虚析构函数 virtual ~Base() = default;,以确保派生类对象在销毁时能够正确调用其析构函数。
  2. 派生类声明

    • Derived 类继承自 Base 类,并重写了 show 函数。
  3. 多态行为

    • 在 main 函数中,创建了一个指向 Derived 对象的 Base 类指针。
    • 通过该指针调用 show 函数,尽管指针类型是 Base*,但由于虚函数机制,实际调用的是 Derived 类的 show 函数。
  4. 析构函数

    • 使用虚析构函数确保在删除基类指针时正确调用派生类的析构函数,避免内存泄漏。

虚表(vtbl)和虚表指针(vptr)

  • 虚表(vtbl):每个包含虚函数的类都有一个虚表,存储该类虚函数的指针。
  • 虚表指针(vptr):每个对象包含一个指向虚表的指针,指向所属类的虚表。

当通过基类指针或引用调用虚函数时,程序会通过对象的虚表指针找到正确的虚表,然后通过虚表找到对应的函数指针并进行调用。这就是虚函数实现运行时多态性的核心机制。

总结

虚函数和虚表机制是C++实现多态性的重要手段。理解它们的工作原理不仅有助于编写更灵活和可扩展的代码,还能帮助我们更好地理解C++语言的底层实现。希望本文能帮助您深入理解C++的虚函数机制,并在实际编程中应用这些知识。

标签:调用,虚表,函数,show,vtbl,C++,派生类,指针
From: https://blog.csdn.net/m0_72877724/article/details/139880623

相关文章

  • Effective C++ 改善程序与设计的55个具体做法笔记与心得 4
    四.设计与声明18.让接口容易被正确使用,不易被误用请记住:好的接口很容易被正确使用,不容易被误用。你应该在你的所有接口中努力达成这些性质“促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容。“阻止误用”的办法包括建立新类型、限制类型上的操作、束缚......
  • C/C++ 堆栈stack算法详解及源码
    堆栈(stack)是一种常见的数据结构,具有"先进后出"(LastInFirstOut,LIFO)的特性。堆栈算法允许在堆栈顶部进行元素的插入和删除操作。堆栈的操作包括:入栈(Push):将元素添加到堆栈的顶部。出栈(Pop):从堆栈的顶部移除元素。取栈顶元素(Top):获取堆栈顶部的元素,但不对其进行删除操作。......
  • C/C++ stack实现深度优先搜索DFS算法详解及源码
    深度优先搜索(DepthFirstSearch,DFS)是一种图遍历算法,它从一个节点开始,通过访问其相邻节点的方式,依次深入到图中的更深层次。Stack(栈)是一种先进后出(LastInFirstOut,LIFO)的数据结构,它非常适合实现DFS算法。首先,我们来解释一下Stack实现DFS算法的原理。DFS算法的核心思想是......
  • 【C++ | 重载运算符】一文弄懂C++运算符重载,怎样声明、定义运算符,重载为友元函数
    ......
  • C++PrimerPlus:第十三章类和继承:抽象基类
    :第十三章类和继承:抽象基类提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加例如::第十三章类和继承:抽象基类提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录:第十三章类和继承:抽象基类前言一、抽象基类总结前言提示:这......
  • 从0开始C++(五):友元函数&运算符重载
    友元函数介绍C++中的友元函数是一种特殊的函数,它可以访问和操作类的私有成员和保护成员。友元函数可以在类的内部或外部声明和定义,但在其声明和定义中需要使用关键字friend来标识。友元函数可以是全局函数,也可以是其他类的成员函数。下面是友元函数的一些重要特点和用法:......
  • c++ 多重包含/定义 || 链接性 || 生命周期
     作用域&&生命周期C++中的作用域(scope)指的是变量、函数或其他标识符的可见和可访问的范围。生命周期(Lifetime)指的是变量或对象存在的时间段。它开始于变量或对象的创建(定义)时刻,结束于其被销毁的时刻。作用域:通过其声明的位置来确定。全局作用域:定义在(类/函数)外部......
  • c++ virtual || virtual =0
    虚函数&&纯虚抽象类:包含纯虚函数的类称为抽象类,继承层次结构的较上层。作用:将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。继承:子类继承基类的成员及成员函数,不可以删除,可以(修改)通过虚函数重写......
  • 【C++】list的使用方法和模拟实现
    ❤️欢迎来到我的博客❤️前言list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素list与forward_list非常相似:最......
  • 2024年华为OD机试真题-分披萨-(C++/Java/python)-OD统一考试(C卷D卷)
    题目描述"吃货"和"馋嘴"两人到披萨店点了一份铁盘(圆形)披萨,并嘱咐店员将披萨按放射状切成大小相同的偶数个小块。但是粗心的服务员将披萨切成了每块大小都完全不同奇数块,且肉眼能分辨出大小。由于两人都想吃到最多的披萨,他们商量了一个他们认为公平的分法:从"吃货"开始,轮流......