虚函数和普通函数的区别
来源:学生作业帮 编辑:神马作文网作业帮 分类:综合作业 时间:2024/11/10 14:25:24
虚函数和普通函数的区别
在VC++深入详解里复习了virtual关键词,然而上次接触这个关键词已经有段时间了,这次虽然似乎是明白了但是希望用自己的话总结一下,但不知道总结的对不对
这里是没在animal类的breathe()里加上virtual前的代码段,输出结果为animal breathe
在加上以后,输出结果为fish breathe
因此我自己的总结是:虚函数是由指针地址中的数据类型来判断函数使用,而非虚函数则是仅仅看指针类型来调用;因此在非虚的情况下调用的是Animal类型,因为指针也是animal类型;而在虚函数的情况下调用的是fish类型的breathe().
不知道以上的思路是否正确?如果不对的话还请帮忙指出错在哪里?
class Animal
{
public:
virtual void Func1();
};
class Fish : public Animal
{
public:
virtual void Func1();
void Func2();
};
int main( int argc, char *argv[] )
{
Animal *an;
Fish *fi;
return 0;
}
--> 第一类:
最简单的 an可以调用Func1(); fi可以调用Func1(); Fun1(); (用的都是自己的)
--> 第二类:
如果设置 an = fi; 结论是: an可以调用Func1(); fi可以调用Func1(); Func2();
如上两种情况所说 其实给进行 an = fi; 其实没啥大用, 因为他们都调用了自己的函数;
但是有一种情况我们是需要解决的 我们希望使用父类的指针来模拟子类的行为
或者说 我们希望使用一根父类的指针 来调用我们在子类里"覆盖"了的函数
那么我们需要使用 "虚函数";
这样我们就可以使用一根父类的an指针 然后来模拟在子类中被 "override" 的函数 Func1();
这就是多态, 在未引入"虚函数"之前 父类总会根据内存模型来调用父类的函数;
引入了"虚函数"之后 父类就会(在运行时采用 "迟绑定")去检查 是否有子类override了父类的virtual函数;
然后确定 调用的是哪一个函数 ( 子类的? 父类的? "子类优先" );
"多态的实现":
当编译器发现一个类中有虚函数时;就会为这个类自动生成一个"虚表" ; 该表是一个一维数组,在这个数组中存放每个虚函数的地址
而且会生成一个"指向虚表指针"; 那么对于父类Animal有一个"虚表", 子类Fish由于一定有虚函数所以也有一个"虚表"
现在在来结合上面的信息; "编译器按照an的内存结构来解释fi"; 这里就发生了"两个动作": ( an小fi大 才会截断 大给小 ok 小给大 GG )
第一个是"内存的截断": 这就解释了为什么fi自己的函数 这里用不了了; 因为内存截断了,( 对于an, fi自己的子类部分成垃圾了 )
第二个是"虚表指针改变": 一开始an的虚表指针应该指向着自己的虚函数, fi的虚表指针也指向了自己的虚函数;
而此时an指向了fi子类对象 当按照an的内存结构解释fi时 解释到的是fi的"虚表"; 所以调用到了fi的虚函数;
类里面的东西非常复杂 . 不是那么简单的判断而已
再问: wow……受教了谢谢谢谢!!!O333O
也就是说
①只有子类存在覆盖了父类函数的情况,且父类是虚函数的情况下才能调用到子类的函数?
②我刚刚的总结不正确,应该是从虚表指针改变来解释an的行为?
_(:3_/ 后面那个多态实现的部分还真的是不知道,看完感觉大概懂了但还是有点迷茫……比如说,为啥按照an的内存结构解释fi的时候,解释到的会是fi的虚表咧……
再答: 这是相对来说的 比如我用父类对象 或者 子类对象 那是自己用自己 和虚函数没关系...
虚函数只发生在 an = fi 这个节点上有意义...
对于子类 他先构造了父类在构造子类 他子类对象的内存模型 是xABCD, 父类对象的是yAB,,, x y分别是虚表指针,. 你说我解释的时候该怎么来 解释yAB是 虚表指针 成员A 成员B ,,, 那么你给往里扣 居然解释到了 yAB 那这时候你还是这么解释 结果就解释到了子类的 这个说的挺啰嗦... 你自己画一个内存模型试试吧 主要是关于指针的
{
public:
virtual void Func1();
};
class Fish : public Animal
{
public:
virtual void Func1();
void Func2();
};
int main( int argc, char *argv[] )
{
Animal *an;
Fish *fi;
return 0;
}
--> 第一类:
最简单的 an可以调用Func1(); fi可以调用Func1(); Fun1(); (用的都是自己的)
--> 第二类:
如果设置 an = fi; 结论是: an可以调用Func1(); fi可以调用Func1(); Func2();
如上两种情况所说 其实给进行 an = fi; 其实没啥大用, 因为他们都调用了自己的函数;
但是有一种情况我们是需要解决的 我们希望使用父类的指针来模拟子类的行为
或者说 我们希望使用一根父类的指针 来调用我们在子类里"覆盖"了的函数
那么我们需要使用 "虚函数";
这样我们就可以使用一根父类的an指针 然后来模拟在子类中被 "override" 的函数 Func1();
这就是多态, 在未引入"虚函数"之前 父类总会根据内存模型来调用父类的函数;
引入了"虚函数"之后 父类就会(在运行时采用 "迟绑定")去检查 是否有子类override了父类的virtual函数;
然后确定 调用的是哪一个函数 ( 子类的? 父类的? "子类优先" );
"多态的实现":
当编译器发现一个类中有虚函数时;就会为这个类自动生成一个"虚表" ; 该表是一个一维数组,在这个数组中存放每个虚函数的地址
而且会生成一个"指向虚表指针"; 那么对于父类Animal有一个"虚表", 子类Fish由于一定有虚函数所以也有一个"虚表"
现在在来结合上面的信息; "编译器按照an的内存结构来解释fi"; 这里就发生了"两个动作": ( an小fi大 才会截断 大给小 ok 小给大 GG )
第一个是"内存的截断": 这就解释了为什么fi自己的函数 这里用不了了; 因为内存截断了,( 对于an, fi自己的子类部分成垃圾了 )
第二个是"虚表指针改变": 一开始an的虚表指针应该指向着自己的虚函数, fi的虚表指针也指向了自己的虚函数;
而此时an指向了fi子类对象 当按照an的内存结构解释fi时 解释到的是fi的"虚表"; 所以调用到了fi的虚函数;
类里面的东西非常复杂 . 不是那么简单的判断而已
再问: wow……受教了谢谢谢谢!!!O333O
也就是说
①只有子类存在覆盖了父类函数的情况,且父类是虚函数的情况下才能调用到子类的函数?
②我刚刚的总结不正确,应该是从虚表指针改变来解释an的行为?
_(:3_/ 后面那个多态实现的部分还真的是不知道,看完感觉大概懂了但还是有点迷茫……比如说,为啥按照an的内存结构解释fi的时候,解释到的会是fi的虚表咧……
再答: 这是相对来说的 比如我用父类对象 或者 子类对象 那是自己用自己 和虚函数没关系...
虚函数只发生在 an = fi 这个节点上有意义...
对于子类 他先构造了父类在构造子类 他子类对象的内存模型 是xABCD, 父类对象的是yAB,,, x y分别是虚表指针,. 你说我解释的时候该怎么来 解释yAB是 虚表指针 成员A 成员B ,,, 那么你给往里扣 居然解释到了 yAB 那这时候你还是这么解释 结果就解释到了子类的 这个说的挺啰嗦... 你自己画一个内存模型试试吧 主要是关于指针的