首页 > 其他分享 >虚函数以及类的强制转换

虚函数以及类的强制转换

时间:2024-03-18 17:12:27浏览次数:24  
标签:转换 函数 子类 void virtual 强制 父类 class

虚函数

类的对象模型

class A{
public:
    void f1(){}
    void f2(){} 
    virtual void f3(){}
    virtual void f4(){}
};

class B{
public:
    void f1(){}
    void f2(){} 
};

class C{

};

int main()
{
    A a;
    B b;
    C c;
    std::cout<<sizeof(a)<<std::endl;
    std::cout<<sizeof(b)<<std::endl;
    std::cout<<sizeof(c)<<std::endl;
    return 0;
}

输出:

我们可以发现空类和只有多个函数的类的对象占的字节都是1
多个虚函数的类的对象占得字节都是8(不同编译环境,这个值不同)

这是因为在一个类中引入一个或多个虚函数时,编译器会插入一个虚函数表指针vptr
且每一个有虚函数的类都有一个虚函数表
类似于如下代码:

class A{
public:
  void* vptr;
};

因为成员变量是占用类的对象的内存空间的,所以sizeof(a)=8

在根据下面这个代码解释一下类A的对象在内存中的布局

class A{
private:
    int m_a;
    int m_b;
public:
    void func1(){}
    void func2(){} 
    virtual void vfunc(){};
    virtual void vfunc2(){}
    virtual ~A(){}
};
int main()
{
    A a;
    std::cout<<sizeof(a)<<std::endl; //输出结果为16,因为两个int(8)+一个virtual(8)
    return 0;
}


虚函数表指针指向虚函数表,虚函数表并不占用类的对象的内存,就像func1()和func()不占用内存一样

多态的使用

# include<iostream>

class Base{
public:
    std::string ISBN;
    virtual void f(){}
    virtual void g(){  //使用virtual,派生类各自定义函数f
        std::cout<<"book"<<std::endl;
    }
    virtual void h(){}
};

class dpar1:public Book{
public:
    void g()
    {
        std::cout<<"ComicBook"<<std::endl;
    }
};

class dpar2:public Book{
public:
    void g()
    {
        std::cout<<"ActionBook"<<std::endl;
    }
};

int main()
{
    dpar1 cb;
    dpar2 ab;
    
    //使用基类引用或指针调用虚函数时,发生动态绑定
    //根据绑定对象的类型,选择函数的版本
    Base* b1 = (Base*)&cb;
    Base &b2 = ab;
    b1->f();
    b2.f();
    return 0;
}

输出结果:


如图,父类Base有三个函数,子类Derive重写了父类的g函数(粉色的部分)

在图中,子类Derive的f和h都指向了父类的两个虚函数,只有g指向了自己重写的虚函数

当子类对象的地址赋值给父类对象的指针时,父类对象的vptr已经是子类的vptr了
所以在执行函数g时是查的子类的虚函数表,执行的是子类重写的函数g

类的强制转换

在上面的例子中,ComicBook可以强制转换为Book

其实在类的强制转换时只转换了基类和派生类共同拥有的东西,在上面的例子中就是ISBN和f()

但如果没有共同拥有的东西(不是父类和子类的关系),则不能进行强制转换

class A{

};

class B{

};

int main()
{
    A a;B b;
    a = (A)b;
}

报错:

标签:转换,函数,子类,void,virtual,强制,父类,class
From: https://www.cnblogs.com/algoshimo/p/18080956

相关文章

  • 代码随想录算法训练营第23天|669. 修剪二叉搜索树|108.将有序数组转换为二叉搜索树|53
    代码随想录算法训练营第23天|669.修剪二叉搜索树|108.将有序数组转换为二叉搜索树|538.把二叉搜索树转换为累加树|总结篇669.修剪二叉搜索树这道题目比较难,比添加增加和删除节点难的多,建议先看视频理解。题目链接/文章讲解:https://programmercarl.com/0669.%E4%BF%A......
  • 函数式编程
    1.持久化数据结构    持久化数据结构的含义是,对于每一个调用者来说,他所使用的每一个数据结构已经持久化了(不可变了),例如f(x)=y,g(y)=z,x、y和z的数据结构已经持久化了,就算其他地方如何去使用,x、y和z都不能有变化。    比如说调用者拥有树1,调用一个方法需要更新树1,那么此时......
  • SQL中的COUNT函数:深入理解COUNT(*)、COUNT(1)和COUNT(字段)的异同与应用
    SQL中的COUNT函数是一个非常强大的聚合函数,它可以用来统计表中满足特定条件的行数。COUNT函数有三种不同的用法:COUNT(*)、COUNT(1)和COUNT(字段),每种用法都有其特定的用途和性能考虑。COUNT(*)COUNT(*)用于统计表中的所有行,不论这些行的值是否为NULL。当你想要得到表中总行数时,......
  • 如何通过ETL做数据转换
    在数字化时代,数据被誉为新时代的石油,而数据的价值往往隐藏在海量数据背后的信息中。然而,海量的原始数据并不总是直接可用的,这就需要一种有效的工具来对数据进行提取、转换和加载(ETL),从而将数据转化为有用的信息。本文将介绍ETL的概念及其在日常生产模式中的重要性,并通过实操演示展......
  • 配置全局变量直接调用函数
    配置全局变量直接调用函数目的想要在项目中使用defs.utills.getFunction()的方式,直接调用我们的函数,不再使用import的方式进行导入,直接在工程化上做手脚进行自动导入解决。过程首先我们在我们的项目框架src/目录下定义一个全局的utill文件,这个我们可以分类型创建文件夹、......
  • 通过视频帧提取及批量取模转换实现基于STC32的点阵LED动画播放
    项目摘要通过视频帧图片提取,图片批量裁剪,转换为BMP文件并取模,获得显示屏代码,基于STC32单片机,在8x8点阵LED模块上实现动画播放。项目方案将目标动图或视频提取为帧图片,可通过MATLAB程序实现;将帧图片裁剪为目标显示屏的像素比例,如0.96英寸OLED显示屏的像素为128x64,......
  • C++中的this指针、访问控制和构造函数
    C++中的this指针、访问控制和构造函数this指针在C++中,this指针是一个特殊的指针,它指向当前对象的地址。每个非静态成员函数(包括成员函数模板)都有一个this指针作为其隐含参数,这意味着在成员函数内部,this可以用来引用调用该成员函数的对象。this指针是自动传递给成员函数的,......
  • 文件描述符(File Descriptor, FD)和 poll 函数简介
    文件描述符(FileDescriptor,FD)是Unix和类Unix操作系统中用于标识进程打开的文件、设备或其他I/O资源的一个抽象概念。它是一个非负整数,由内核在进程打开或创建一个文件时分配给该进程。当应用程序通过系统调用如open()、socket()等操作打开一个现有文件、创建新文件或者创......
  • 记录一下时间戳转换方法
    /***时间戳格式化函数*@param{string}format格式如('Y-m-d')*@param{number}timestamp要格式化的时间默认为当前时间,必须为number类型,字符串将返回NAN*@return{string}格式化的时间字符串,(按照上面的格式返回结果可以为'2023-01-01')......
  • 内存函数(C语言)
    文章目录内存函数memcpymemmovememsetmemcmp内存函数使用内存函数需要包含头文件<string.h>memcpy将内存的数据拷贝到新空间void*memcpy(void*destination,constvoid*source,size_tnum);memcpy函数能将源地址后num个字节的数据拷贝到目标空间区别内存......