关于晚绑定,100分答谢

fang_jb 2002-04-09 09:25:38
晚绑定的意思就是说执行期才确定所调用的函数的准确地址?
引发多态最关键的一点就是使用基类指针去寻找派生类的地址,
去调用派生类的函数?

想请问的是,这样的东西算不算多态
class A
{
public:
int run(){aa()};
virtual void aa(){};
};
class A_1 : public A
{
public:
void aa(){};
};

func()
{
A *p;
A_1 a1;
p = &a1;
p->aa();
// A_1 a1;
// a1.run();
}
我知道在这个时候调用的应该是A_1::aa();
那这样做的目的是什么?这样和注释掉的部分有什么区别?
未注释部分的哪里有晚绑定的痕迹?难道就是p=&a1就使得地址无法确认而
非得到运行期才知道?a1既然已经被实例了,为什么就找不到A_1::aa()呢?

而注释掉的部分是不是多态的用法?感觉上不象,因为run()已经被继承下来了,
所以用A_1对象的时候肯定调的A_1::aa(),对吗?

还有就是,比较正常的做法是不是象这样
func(A* p)
{
p->aa();
}
然后外面有个地方
A_1 a1;func(&a1);
这样做是不是多态?这样做我觉得和前面的没注释的部分一样
只是一个直接定义了类型的转换,一个是编译器控制的类型转化,对吗?

以上请教各位,呵呵,好象多了点
不过请麻烦不要让我去看什么书啦,看什么文档之类的,
我能找到的东西我基本都看了,只是还是觉得以上地方怪怪的,
对晚绑定的存在感到很奇怪,有什么东西在编译期找不到地方呢?
还是说我对晚绑定的定义,也就是对执行期绑定的定义没吃准?
那各位谁能给个明白点的答案,小的多谢了,毕竟郁闷了好多天了
...全文
66 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
fang_jb 2002-04-12
  • 打赏
  • 举报
回复
runtime到底什么意思?程序开始执行的时候?程序链接成可执行的时候?
那岂不是和dll一个概念?到了执行到的时候再步入相应
的内存地址?
哪里有编译原理那类的东西?或者哪里有类似c++编译器的工作手册
之类的东西?呵呵
我觉得linker应该可以解决绑定的,程序不管有多少判断,
不管有多少用户输入,总是有各种路径可以完成执行的,
如果linker都不知道的话,那程序怎么执行?至少我觉得linker
应该已经预先设定所有的路径,到时候需要决定的只是根据输入的内容,
选择路径罢了。
程序在最终执行的时候我觉得应该是一个选择路径而不是创造路径的过程
(仅针对我理解中的绑定)

这样对吗?
fang_jb 2002-04-12
  • 打赏
  • 举报
回复
因为程序路径的复杂性,也因为有执行期绑定函数的能力,
所以编译器都选择了runtime处理问题的简化解法,由于更符合
习惯和简易的原则,而晚绑定就是基于这一简化问题的目的
而产生的能力,也可能是对于处理不确定选择的更好的途径,
而virtual就是为了告诉编译器我需要这种能力的方法。
只是一种想法而已,没有想象的那么复杂,对吗?

我觉得这样理解起来似乎变得很简单,那么这样对吗?

anyway,谢谢先,给分了,如果愿意的话,继续···
prototype 2002-04-12
  • 打赏
  • 举报
回复
also, worse, the dynamic binding is very likely related to
the input from the environment. the compiler has no way to
figure that part out. consider the following code:

class base;
class A : public base;
class B : public base;

void funct( base* p ) { /* ... */ }
...

int i;
cin >> i;

base* p;

if (i == 0) p = new A;
else p = new B;

funct( p ); // no way to know what is passed to 'funct' at compile time.
prototype 2002-04-12
  • 打赏
  • 举报
回复
runtime意思: 执行的时候.

我觉得linker应该可以解决绑定的,程序不管有多少判断
this problem is not as simple as you think. it means the compiler has to be able to do global optimization. this is very hard. and not supported by most of the current compilers.
you can image how complex it could be if you do global optimization for the windows xp... geee.



fengye 2002-04-10
  • 打赏
  • 举报
回复
编译单元(translation unit), 简单来说就是把include都展开后的cpp文件.

现在的compiler能看到的所有信息都只限于这个编译单元, linker可以看到全部obj代码, 虽然有可能把一部分动态绑定解决为静态绑定, 但不可能解决所有的绑定.

如void func( A* p )中的p, 如果是根据用户输入1还是2来决定传入A_1*或A_2*, 那么就不可能在编译时静态解决绑定.

prototype 2002-04-10
  • 打赏
  • 举报
回复
晚绑定到底是在什么时候发生的?

runtime. think about the following example:

class A;
class B : public A;
class C : public A;

...

void func( A* p );

// 'func' never knows what is passed to itself (C* or B*
or A*) until runtime.

fang_jb 2002-04-09
  • 打赏
  • 举报
回复
突然间我发现我的问题在哪了,

我想我的问题应该是,晚绑定到底是在什么时候发生的?
执行期到底是什么时候?链接成exe的时候还是真正有人执行这个程序的时候?
如果是在链接的时候,我想我应该知道是怎么回事了,
手头没有编译原理之类的书,哪位明白这个,谢谢了

不久给分!!呵呵
papercrane 2002-04-09
  • 打赏
  • 举报
回复
p->aa()被预编译为
(*A::vtable[p->vtpr[1]])(p);
仅此而已。
fang_jb 2002-04-09
  • 打赏
  • 举报
回复
to fengye()
我觉得你说的很对,从道理上来讲,在编译class A的时候
编译器是不知道该调用哪个aa(),那个aa()都有可能正在被我vi着,
不过我在想,在整个程序在链接成可执行程序的时候,这个时候的执行码
是不是已经知道了该执行哪个aa()?
那也就是说,执行期的晚绑定不过是指在生成可执行程序的动作罢了,
而不是dll的类似概念,对吗?我没看过编译原理之类的东西,不要砍我。

还有你的编译单元什么意思?
fang_jb 2002-04-09
  • 打赏
  • 举报
回复
to afsfop()

那本书说的对不对呢? :)
fang_jb 2002-04-09
  • 打赏
  • 举报
回复
to aileen_long(期待2002)
关于你的例子,我想我明白,我也会写,如果让我写我也这么写,

可好象你的例子和我的是一回事,只是告诉我该这样写,
可没告诉我为什么要这样写。

晚绑定的特点就是以时间换空间,以效率为代价来换取代码的简洁。

这句话有一定道理,不过我总觉得在我的问题里不太对的上,
不好意思,只是这样感觉,我的想法和你一致,但是我想知道为什么要这样!
IT_worker 2002-04-09
  • 打赏
  • 举报
回复
我要加两句的是p->run()也是晚绑定。
而且我常常用这种方法写一些函数
fengye 2002-04-09
  • 打赏
  • 举报
回复
考虑这种情况,你在编写A::run()或者后面所说的func(A*)的时候,你还不知道有A_1,这时候你仍然可以写A::run()和func(A*),然后编译。

对于编译器来说,编译A::run()和func(A*)的时候不需要知道有没有子类,也不可能知道,因为你以后还可能扩展。而扩展的时候,A::run()和func(A*),应该不需要重新编译,除非你设计有问题。

编译器在看到A* p = new A_1以后p还认为是指向A的指针,这句话是正确的。如果说这时候编译器还是有机会知道p真正指向的是什么类型的话,那么经过多次赋值、传参等过程,编译器就很难再知道了,尤其是超出这次编译单元之后。
aileen_long 2002-04-09
  • 打赏
  • 举报
回复
所谓晚绑定,不是说编译器无法找到某个函数的入口地址,而是说我们不希望被virtual修饰的函数在编译期间就受指针类型的限制,而过早确定(早绑定)。这里可以举一个例子来说明晚绑定在特定的时候是非常方便的。
假设一个程序需要根据用户的输入计算长方形(用class CRectangle描述)或者圆形(class CCircle描述)的面积,程序要实现在接受用户输入的若干笔数据后再全部计算的功能。由于有存储的数据长度不定,因此比较合理的做法应该是,用链表的形式来存储(STL的list也很方便)。
那么,为前面的两个类再定义一个抽象基类CBase,它什么也不做,只有一个纯虚函数CaleArea,而CRectangle和CCircle分别重载该虚函数,存储数据时,只需要把指向CRectangle或CCircle对象的CBase类型的指针以及相关参数加入链表。计算时,仍然以CBase*类型导出对象,并以该指针来访问CaleArea即可,这里即实现了晚绑定。
晚绑定的特点就是以时间换空间,以效率为代价来换取代码的简洁。
fang_jb 2002-04-09
  • 打赏
  • 举报
回复
to cqtine(河沙)
但从编译的角度看,前者在编译后还不能确定 p->aa() 调用的是哪个类的方法

为什么不能?可以告诉我这时候编译器做了什么吗?
fang_jb 2002-04-09
  • 打赏
  • 举报
回复
to afsfop() :
但在编译时,p被认为是作为指向A的对象的指针,无法正确调用A_l::aa(),所以必须在运行时鉴定

我觉得很有道理,不过我不知道你能不能肯定这句话是对的,
我不知道编译器在看到 A* p = new A_1 的时候都做了什么,
谁知道?可以说来听听吗?
我想如果这句话是对的话,我就能理解到底发生了什么了,谢谢
不过分给不给可就得看这句话了,呵呵。
maoliao 2002-04-09
  • 打赏
  • 举报
回复
gz
cqtine 2002-04-09
  • 打赏
  • 举报
回复
你提供的例子很简单,p = &a1; p->aa(); 和 A_1 a1; a1.run(); 表面上看是没有多少区别;
但从编译的角度看,前者在编译后还不能确定 p->aa() 调用的是哪个类的方法,而后者就能够确定,因为编译完成,相应的连接地址都已经确定;

至于晚期帮定的意义:当很大的类体系时(巨大),你知道该基类有某一种方法,该方法在各个派声类中实现大致相同的功能,但又不完全一样时,你就回体会到这种机智的好处:仅用基类的指针,去调用其所有的派生类的方法(当然要Virtual and overload );



cssnow 2002-04-09
  • 打赏
  • 举报
回复
1.晚绑定是动态多态性
2.C++实现是VPTR + VTABLE
3.VTABLE在运行时动态分配
4.对虚函数的调用必须通过VPTR访问到VPTR中的虚函数地址。
pjohnlei 2002-04-09
  • 打赏
  • 举报
回复
当基类中的指针指向派生类对象的时候,等于已经指向了派生类对象的虚函数表的指针.这是实现多态的一个基本.
加载更多回复(1)

69,381

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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