虚拟函数问题

j8daxue 2009-04-12 08:40:37
问题如下

class A{
public:
A(){
FA();

}
virtual void FA(){
cout<<"A::FA"<<endl;
}
virtual void FB(){
cout<<"A::FB"<<endl;

}
};

class B:public A{
public:

B(){
FA();
}
virtual void FA(){
cout<<"B::FA"<<endl;
}
virtual void FB(){
cout<<"B::FB"<<endl;
}
};
void main(){
A *p =new B;
}

输出将是A::FA
B::FA
在派生类构造函数先调用父类构造函数,
但父类构造函数里调用FA(),感觉这里的指针实际是B的呀?为什么调用的是A的FA?

如果能说明整个过程的话,50分.
...全文
147 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
tian_yang_jian 2009-04-13
  • 打赏
  • 举报
回复
虚函数和多态关联,运行的时候调用;再者,多态和继承关联,没有继承就不会有多态。
这里是子类的虚函数覆盖父类的虚函数,因此子类中覆盖父类的虚函数前可以不加virtual。
你要记住一句话“子类有的调用子类的,子类没有的调用父类的”;是子类调用父类而不是
父类调用子类,箭头是向上的而不是向下的。下面是对你问题的分析:
首先,父类的函数
A(){ FA(); } 调用本类的FA(),因为箭头不会向下,即父类不会调用子类虚函数,
所以执行:cout < <"A::FA" < <endl;

其次,子类的函数
B(){ FA(); } 先检查本类有没有虚函数FA(),因为有,所以执行:cout < <"B::FA" < <endl;
如果你把子类本身的FA()函数注释掉,你再执行本程序,输出结果一定是:
A::FA
A::FA
tian_yang_jian 2009-04-13
  • 打赏
  • 举报
回复
虚函数和多态关联,运行的时候调用;再者,多态和继承关联,没有继承就不会有多态。
这里是子类的虚函数覆盖父类的虚函数,因此子类中覆盖父类的虚函数前可以不加virtual。
你要记住一句话“子类有的调用子类的,子类没有的调用父类的”;是子类调用父类而不是
父类调用子类,箭头是向上的而不是向下的。下面是对你问题的分析:
首先,父类的函数
A(){ FA(); } 调用本类的FA(),因为箭头不会向下,即父类不会调用子类虚函数,
所以执行:cout<<"A::FA"<<endl;

其次,子类的函数
B(){ FA(); } 先检查本类有没有虚函数FA(),因为有,所以执行:cout<<"B::FA"<<endl;
如果你把子类本身的FA()函数注释掉,你再执行本程序,输出结果一定是:
A::FA
A::FA

j8daxue 2009-04-13
  • 打赏
  • 举报
回复
6-9楼的朋友们,我想讨论的不是虚函数的怎么理解,我也不是初学者,而是针对这个问题的流程以及我的疑问.
tian_yang_jian 2009-04-13
  • 打赏
  • 举报
回复
楼主,你好好看看我给你的答复,你应该可以看懂解决了你的问题。
你说构造的问题,我研究的也不太深,但我们不能光看书,也要有自己的理解。

构造肯定是先构造父类,没有父亲哪有儿子啊。但儿子有比父亲更强的功能,父亲的功能一点也没有少。

但调用应该是反过来的啊,就是构造从功能小的开始构造,不可能把功能强的构造成弱的吧?再者调用好比用人,
你说用牛逼人呢,还是用不牛逼的人。儿子比老子牛逼,肯定先用儿子,儿子不在才用老子也可以勉强过去。再说老子
做的事情儿子都可以做,那假如都用的话,不就多余了吗?


我的意思是说构造从基类开始,调用是从自己类开始向上沿路行走,依次寻找,找到为止。


8楼9楼都是我,发重复了,希望你好好看看。呵呵,很少发帖,希望给于关注。谢谢
oyljerry 2009-04-12
  • 打赏
  • 举报
回复
构造函数是先要调用基类构造,所以先调用A的A::FA,然后构造B滋生的对象,因而B的构造函数中调用B中实现的方法...
wanjingwei 2009-04-12
  • 打赏
  • 举报
回复
调用虚函数是运行时绑定,所以是由内存里实际保存的类型决定
调用非虚函数是编译时绑定,编译器不知道内存里实际保存的类型,所以是由定义的类型决定
j8daxue 2009-04-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cnzdgs 的回复:]
构造对象时先执行基类的构造函数,然后再执行派生类的构造函数,在执行基类的构造函数时,派生类的虚表尚未建立,此时调用虚函数是调用基类的函数,所以先输出A::FA,在执行派生类的构造函数时,派生类的虚表已经建立,此时调用虚函数是调用派生类的函数,所以输出B::FA。
[/Quote]
那是不是在构造函数的时候先创建基类的虚函数表,这时调用的就是基类的虚函数,
之后执行自己的构造函数时,覆盖基类的虚函数表而形成自己的虚函数表?
黄志义 2009-04-12
  • 打赏
  • 举报
回复
正解
[Quote=引用 2 楼 cnzdgs 的回复:]
构造对象时先执行基类的构造函数,然后再执行派生类的构造函数,在执行基类的构造函数时,派生类的虚表尚未建立,此时调用虚函数是调用基类的函数,所以先输出A::FA,在执行派生类的构造函数时,派生类的虚表已经建立,此时调用虚函数是调用派生类的函数,所以输出B::FA。
[/Quote]
fandh 2009-04-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cnzdgs 的回复:]
构造对象时先执行基类的构造函数,然后再执行派生类的构造函数,在执行基类的构造函数时,派生类的虚表尚未建立,此时调用虚函数是调用基类的函数,所以先输出A::FA,在执行派生类的构造函数时,派生类的虚表已经建立,此时调用虚函数是调用派生类的函数,所以输出B::FA。
[/Quote]
同意!
cnzdgs 2009-04-12
  • 打赏
  • 举报
回复
构造对象时先执行基类的构造函数,然后再执行派生类的构造函数,在执行基类的构造函数时,派生类的虚表尚未建立,此时调用虚函数是调用基类的函数,所以先输出A::FA,在执行派生类的构造函数时,派生类的虚表已经建立,此时调用虚函数是调用派生类的函数,所以输出B::FA。
warmyellow 2009-04-12
  • 打赏
  • 举报
回复
不用关键字virtual也是一样的结果,因为继承的类的地址那个空间包含其父类的地址空间 说白了继承类只是把父类做的更大了扩展了些而已所以要先调用父类的构造函数, 而virtual关键字的运用是会建立一个虚拟函数表,一个父类的实例化,在通过该对象调用virtual函数将会查询那个虚拟函数表查找最顶层的子类的这个同名函数。

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧