c语言中怎么理解逻辑值(C类和对象)
c语言中怎么理解逻辑值(C类和对象)然后我们通过例子去看 多态的实现原理.然后子类还要必须去重写父类中的虚函数 不重写虚函数的话 那叫做 函数地址早绑定.对吧.然后要使用多态的话 需要让父类的指针或者引用 指向子类的对象对吧.并且我们提出了 重写的概念.
然后我们再去看c 中 多态实现的原理.
前面我们说 多态有 静态多态和动态多态 然后并且使用了一下多态 做了个案例.
并且我们说 多态的实现需要满足条件 就是首先要有继承关系 要有父类 子类
然后子类还要必须去重写父类中的虚函数 不重写虚函数的话 那叫做 函数地址早绑定.对吧.
然后要使用多态的话 需要让父类的指针或者引用 指向子类的对象对吧.
并且我们提出了 重写的概念.
然后我们通过例子去看 多态的实现原理.
首先去看 上节课我们用到的这个Animal类 然后
里面有个spreak这个 虚函数.这个animal类就是我们的父类.
然后我们再去看 上面这个猫类 它继承了父类animal类
Cat类中重写了 父类Animal类中的spreak()方法.
然后狗类 也重写了animal中的spreak方法.
然后上面我们就是 通过地址晚绑定 动态多态的方式 实现了
我们给doSpreak方法 传入我们的子类对象 用父类引用来接收 实现对
子类中的重写方法的调用.
那么这个过程的原理是什么?
首先我们 去写个test02方法 然后 调用test02方法 打印Animal类的size 大小.
首先我们去 打印animal这个父类的大小 但是打印之前我们先把
父类中的 spreak函数 前面的virtual 关键字 给删除掉.
我们再去打印.
执行可以看到 只有个函数的地址对吧 可以看到animal这个时候的
大小是一个字节.用来区分对象用的.
然后如果我们在animal类的spreak方法前面 加上virtual这个关键字 然后再去打印.
我们再去看看 结果是4个字节了. 那么这4个字节是什么呢?
int float是4个字节?对吧 ....指针也是4个字节.
对这个4个字节 其实就是指针.
我们去看原理 当我们在Animal类中的spreak函数 前面 添加virtual关键字的时候
我们可以看到 这个时候Animal类的内部结构是上面 右边这样的.
首先Animal中会有一个vfptr 这个指针 这个指针vfptr的意思是
v - virtual
f-function
ptr - pointer
是虚函数指针的意思.
然后这个vfptr指向的是vftable 这个虚函数表 这个表是干什么用的呢?
这个表是记录了虚函数的地址.
比如 我们去看animal类的内部结构 可以看到 当我们在父类animal类中 的spreak函数的前面
添加virtual关键字的时候 他会产生一个vfptr 这个指针 这个指针会指向vftable一个虚函数表的地址
然后这个表中 这个时候会存放animal类的 虚函数spreak()的地址 也就是&Animal::spreak.
当我们再去写一个Cat类 来继承这个Animal类的时候 在Cat这个子类中 去重写Animal类中的spreak函数
可以看到由于cat类继承了Animal类 所以 在Cat类的结构中 也有个vfptr 然后这个vfptr 也是指向一个vftable表
然后这个vftable表中 也是存放了一个&Animal::spreak 这个父类的spreak方法的指针 这个是继承过来的.
然后这一步很重要 可以看到由于Cat重写了父类中的spreak函数 所以 在Cat类的内部结构中的vftable 虚函数表中
继承过来的&Animal::spreak函数的地址 就会被替换成&Cat::spreak
而这个过程是在 当我们 调用doSpreak 给参数Animal这个父类的引用 传递一个cat这个子类对象的时候
发生的.
可以看到上面也说了 当父类的指针 或者引用 指向子类的对象的时候 就会发生多态 实际上就是
会把继承过来的 父类的&Animal::spreak 这个虚函数的指针替换成
&Cat::spreak 这个子类的spreak的地址.
这样就可以实现 我们执行的时候 传入的是子类的对象 打印出来 就是子类对象中 重写的那个spreak方法的内容了.
我们也可以打开工具去看一下具体情况.
首先我们去把virtual 关键字 删除掉.
可以看到 我们暂时把父类的虚函数spreak 前面的virtual删除掉.
我们找到对应的代码文件
用工具 走到对应文件 目录 先查看一下
然后我们 执行
cl /dl reportSingleClassLayoutAnimal "01 多态基本概念.cpp"
执行以后 可以看到这个时候如果我们不给父类的spreak函数 前面 添加virtual的情况 可以看到这个时候
animal类的大小是
size(1);1个字节.
然后我们再去打开
animal类中的spreak方法 前面的virtual 然后再去用工具去查看一下Animal类的 结构
可以看到这个我时候size变成了4个字节 然后 里面有vfptr 然后vfptr指针 指向
vftable这个虚函数表 然后可以看到虚函数表中 存着&Animal::spreak这个指针.对吧.
我们可以对着去看看 可以看到在Animal类中 当spreak前面加上virtual关键字的时候 类的结构就会有vfptr这个指针 然后
这个指针指向一个vftable这个虚函数表 然后
这个虚函数表中存放着&Animal::spreak这个父类中spreak函数的指针.
然后我们再去看看 当我们把Cat类中的 重写的父类中的这个spreak函数 删除掉.
我们去查看Cat类的 对象结构去.
可以看到这个时候得到的结构 Cat类的大小是字节4个.里面有个vfptr指针
这个指针指向一个vftable虚函数表 然后
虚函数表 中存放了&Animal::spreak 这个父类的spreak函数的指针对吧.
因为我们在子类中没有重写父类的spreak函数.所以这里 Cat类的虚函数表中 存放的是继承过来的 父类的
&Animal::spreak函数的指针.
当我们把Cat类中的 重写了父类中的是spreak的函数的注释打开 然后我们再去执行分析一下.
可以看到这个时候
Cat类 的size大小还是4个字节 存放了vfptr 这个指针 然后这个指针指向了vftable 这个虚函数表
然后这个虚函数表中 注意 这时候 存放的指针 就是
&Cat::spreak 这个Cat子类中的spreak函数了.