虚函数问题?我的观点是否正确?

allen_zhaozhencn 2003-10-24 09:05:27
试看下面的代码:
class base
{
public:
virtual void test() { ; } ;
};

class derived:public base
{
public:
void test() { ; };
virtual void test___2() { ; };
};

void main()
{
base *p=new derived;
p->test(); //OK!
p->test__2(); //error! why?
}
我的问题是:
p->test__2() ;
观点:
1 通过基类指针调用test__2时,p->vptr实际上使用的是derived的vptr.
2 p的静态类型为base,所以当调用只在derived中声明的虚函数test__2时,在base中没vtbl中找不到该函数,也就是无法确定该函数的slot值,从而调用会出错。(注:多态的类(即含有虚函数)的vtbl是在编译阶段由编译器完成构建的。)




...全文
25 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
aaassd 2003-12-23
  • 打赏
  • 举报
回复
第二个方法不能正确调用,也很正常,因为虚函数表中没有该方法?

在thinking in c++中好像不是这样说的.
5852 2003-12-21
  • 打赏
  • 举报
回复
我较欣赏 byry(pepsi) 的解释
一个傻冒 2003-12-21
  • 打赏
  • 举报
回复
声明指针时所用的类型,已经为指针指明了一块内存结构.既然是用base做指针类型,那p必然会指向base的内存结构,自然不会访问到derive类中的函数.
BinaryWorld 2003-12-21
  • 打赏
  • 举报
回复
base *p=new derived;
p是base类型指针,但指向derievd类型的结构是正确的。
也是p是base类型,但p的内存结构是derived的内存结构。
在执行的时候,如果p的调用方法不是虚态的,则调用的时候只调用p的方法,如果是虚态的则调用的时候,采用的是 后期绑定也就是动态绑定 的方法,编译器根据每个类型的标记(这个根据编译器来定)来捆绑设置具体的执行方法。

第二个方法不能正确调用,也很正常,因为虚函数表中没有该方法
aaassd 2003-12-20
  • 打赏
  • 举报
回复
mark
chengwu 2003-12-17
  • 打赏
  • 举报
回复
base *p=new derived, p的虚函数表是子类的,这是在new的时候确定的
之所以p->test__2();有错是因为在编译时,编译器在base的class里头找不到这个函数,这是个编译的错误,在vc里头只要有一个强制类型转换就可以编译通过了
zhangwendi 2003-12-17
  • 打赏
  • 举报
回复
对象的虚函数列表里找不到test___2(),因此没有入口地址
hhb 2003-12-17
  • 打赏
  • 举报
回复
但是基类的vtbl不应该被继承类改变的啊,所以应该是在继承类自己的vtbl加一笔记录吧
hhb 2003-12-17
  • 打赏
  • 举报
回复
vtbl中的放的实际就是函数的偏移值,而且如果继承类也有不同名的virtual 函数的话
那继承类也有自己的vbtl表;否则就在基类的vtbl多加一笔记录,表示继承类的该同名函数的
偏移值.
不知我的理解对否?
wangyangcheng 2003-12-17
  • 打赏
  • 举报
回复
借樓主的寶地一用,請大俠看看這一話對否﹕

除非在類中聲明的函數為pure virtual member function,否則必須要給出其定義﹐包括vitual member function.

Thanks!
chengwu 2003-12-17
  • 打赏
  • 举报
回复
用((derived *)p)->f()这种形式在vc下就可以了

base *p的时候只不过分配了4个字节的空间,根本没有什么虚函数表,只有在new derived的时候编译器才会将derived的虚函数表给p,所以p的虚函数表是子类的
wangyangcheng 2003-12-17
  • 打赏
  • 举报
回复
TO: stephenland74(程序员)
dynamic_cast<derive*>(p)->test_2()

你的方法好像通不過﹗(VC6和Dev-Cpp下面都一樣)
codelover 2003-12-17
  • 打赏
  • 举报
回复
这样肯定是错的啊,Base里面根本就没有暴露函数_test_2()的接口,也就是说Base的
虚函数表里面根本就没有_test_2()的地址啊。你是不是认为p实际指向的是derived,所以编译器应该能找的这个函数的地址? 不对,p声明的是Base*, 只不过他隐含的指向Derived*是安全的,Base*中的虚拟函数在Derived中肯定存在。但是Derived中的函数在Base中不一定存在。
byry 2003-11-03
  • 打赏
  • 举报
回复
你可以把例子这样写:
class base
{
public:
virtual void test() { cout<< "Base Class" << endl; }
};

class derived:public base
{
public:
void test() {cout<< "Derived Class" << endl;}
virtual void test_2() { ; }
};

void main()
{
base *p=new derived;
p->test(); //Derived Class
p->test_2(); //error
}

当p->test()时,输出结果是Derived Class,这说明虚函数调用成功
函数Derived::test()覆盖了Base::test(),所以结果为Derived Class

如果在base类中没有把test()定义为虚函数的话,输出结果就为Base Class
所以,关键在于是否将其定义为虚函数。

至于为什么p->test_2()是个错误,这是因为,基类指针只能调用基类自己定义的函数,
而不能调用基类中没有声明的函数。

有空可以看看 函数(虚函数)映射表,就晓得为什么了,还有林锐的《高质量C++/C编程指南》,里面讲的也很清楚
jenny1982 2003-11-03
  • 打赏
  • 举报
回复
我认为virtual是多余的,因为根本就不是多态行为(两个函数名不同),

p是基类指针,不能指向test_2();
robertnet 2003-11-01
  • 打赏
  • 举报
回复
指针p是base类之指针对象,此指针指的是虚函数表不具有test__2()函数
还有一点,楼主的定义和调用的test__2()函数名不同.
killme2008 2003-11-01
  • 打赏
  • 举报
回复
可以把派生类指针赋给基类就可以了,这就是多态
killme2008 2003-11-01
  • 打赏
  • 举报
回复
为什么要理解的这么复杂?
我的理解是:
base *p=new derived;
base是p的形式类型,而derived才是p的实际类型,使用p->test__2();
会对形式类型进行类型检查,base没有test_2()方法,所以出错。
panzhaoping 2003-10-28
  • 打赏
  • 举报
回复
同意,还有hust出版社,妈的。要我老命
不过。那本深度探索c++对象模型的确不错
overawe 2003-10-25
  • 打赏
  • 举报
回复
再说一句 妈的 是么书只要一和候节占边 都他妈的贼贵...!!!!!
加载更多回复(14)

64,650

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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