IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 使用c语言实现c++中虚函数机制 -> 正文阅读

[C++知识库]使用c语言实现c++中虚函数机制


前言

众所周知C++是门面向对象的语言,其中三大特性是继承、封装和多态。多态又分为动态和静态多态两种,其中静态多态指重载和隐藏,而动态多态指虚函数机制。本篇主要介绍动态多态的虚函数机制。


一、虚函数机制

? 虚函数是指基类中使用virtual关键字修饰的成员函数,如果基类未实现该虚函数,则成为抽象类,抽象类不能直接实例化,并且如果派生类继承虚函数,必须实现基类的虚函数才能实例化,这个实现过程也叫重写。
?如何体现其动态特性能呢?其实是因为面向对象编程的过程中,如果希望基类指针指向不同派生类时,希望其可以调用不同派生类中的函数而不是基类的函数,可以通过将基类中的函数声明为虚函数达成。
?具体实现机制如下:编译器为每个具有虚函数的基类生成一个虚函数表,不同类有不同的虚函数表,同一个类的不同对象共享一个虚函数表。继承这种基类的派生类在实例化时,会多出一个虚表指针指向对应类的虚函数表,因此即使派生类被转化成基类指针,其虚表指针依然能帮助指向对应派生类的函数

二、C++实现虚函数

class ISpearker
{
protected:
    size_t id;
public:
    ISpearker(size_t id) :id(id) {}
    virtual void speak() = 0;
    virtual void walk() = 0;
};

class Dog : public ISpearker
{
public:
    Dog() : ISpearker(0) {}
    void speak()
    {
        printf("id: %d, dogs say woof \n", this->id);
    }

    void walk()
    {
        printf("id: %d, dog is walking\n", ((__dog*)ptr)->id);
    }
};

class Human : public ISpearker
{
public:
    Human() : ISpearker(1) {}
    const char* name;
    void speak()
    {
        printf("id: %d, human %s say hello \n", this->id, this->name);
    }

    void walk()
    {
        printf("id: %d, human %s is walking \n", this->id, this->name);
    }
};

int main()
{

   //test();

    Dog dog;
    Human human;
    ISpearker* speaker_dog = static_cast<ISpearker*>(&dog);
    ISpearker* speaker_human = static_cast<ISpearker*>(&human);
    speaker_dog->speak();
    speaker_human->speak();
    speaker_dog->walk();
    speaker_human->walk();
    
}

运行结果:
在这里插入图片描述

三、C实现虚函数

//创建一个结构用于存储不同虚函数地址
struct SpeakerTable
{
    void(*speak)(void* ptr);
    void(*walk)(void* ptr);
};

//基类对象,如果是纯虚函数, 因为不能实例化,即无法谈论有无虚函数指针
struct __ispeaker
{
    const SpeakerTable* vfptr;
    size_t id;
};
//子类对象Dog,必须实现基类纯虚函数,否则不能实例化,实例化之后的对象存在虚函数指针,
//虚函数指针指向Dog类对应的虚函数表,此处位__dogSpeakerTable
struct __dog
{
    const SpeakerTable* vfptr;
    size_t id;
};
//子类对象Human,必须实现基类纯虚函数,否则不能实例化,实例化之后的对象存在虚函数指针,
//虚函数指针指向Human类对应的虚函数表,此处位__humanSpeakerTable
struct __human
{
    const SpeakerTable* vfptr;
    size_t id;
    const char* name;
};

//编译阶段所有类对应虚函数地址(__dog_speak, __dog_walk, __human_speak,__human_walk)均已经确定
void __dog_speak(void* ptr)
{
    printf("id: %d, dogs say woof \n", ((__dog*)ptr)->id);
}

void __human_speak(void* ptr)
{
    __human* human = (__human*)ptr;
    printf("id: %d, human %s say hello \n", human->id, human->name);
}

void __dog_walk(void* ptr)
{
    printf("id: %d, dog is walking\n", ((__dog*)ptr)->id);
}

void __human_walk(void* ptr)
{
    __human* human = (__human*)ptr;
    printf("id: %d, human %s is walking \n", human->id, human->name);
}

//虚函数表,编译阶段将对应虚函数地址存入对应类的虚函数表,每一个类对应一个虚函数表,所有相同
//类型对象共享一个虚函数表,this指针区分相同类型的不同对象
const static SpeakerTable __dogSpeakerTable = { __dog_speak, __dog_walk };
const static SpeakerTable __humanSpeakerTable = { __human_speak, __human_walk };

//实例化,分配地址,给虚函数指针分配对应虚表地址,初始化成员变量
__dog* createDog(size_t id)
{
    __dog* dog = (__dog*)malloc(sizeof __dog);
    dog->vfptr = &__dogSpeakerTable;
    dog->id = id;
    return dog;
}

__human* createHuman(size_t id)
{
    __human* human = (__human*)malloc(sizeof __human);
    human->vfptr = &__humanSpeakerTable;
    human->id = id;
    human->name = "tom";
    return human;
}

void test()
{
    __dog* dog = createDog(0);
    __human* human = createHuman(1);

    __ispeaker* idog = (__ispeaker*)dog;
    __ispeaker* ihuman = (__ispeaker*)human;

    // 编译器根据基类指向的虚函数不同,虚函数指针调用的虚函数不同,ispeaker->speak;
    idog->vfptr->speak((__dog*)idog);
    ihuman->vfptr->speak((__human*)ihuman);

    // ispeaker->walk;
    idog->vfptr->walk((__dog*)idog);
    ihuman->vfptr->walk((__human*)ihuman);
}

int main()
{

   test();

    //Dog dog;
    //Human human;
    //ISpearker* speaker_dog = static_cast<ISpearker*>(&dog);
    //ISpearker* speaker_human = static_cast<ISpearker*>(&human);
    //speaker_dog->speak();
    //speaker_human->speak();
    //speaker_dog->walk();
    //speaker_human->walk();
    
}

运行结果:
在这里插入图片描述


总结

深化对C++虚函数机制

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:17:37  更:2022-04-22 18:19:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:51:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码