要有virtual,及如何理解晚捆绑

下边要说的是我在语言学习过程中遇到一些不理解的问题,为什么要有virtual机制,还有什么是晚捆绑。我当时学到这的时候可能困惑了一段时间,后来经过继续学习测试等,得出了自己的结论,仅在这记录一下。没有太多的代码实例,更像是我在啰嗦一些东西。

先说virtual

说道virtual肯定就想到多态,virtual是c++ 实现多态的一种方法,为什么要有这样一套虚机制? 还是那些原则,代码复用 ”想用不变的代码去实现不同算法“,大概就是 懒吧。

举个简单的例子,(可能我现在在站的高度不够,理解范围有限,但这个例子至少是虚机制想要解决的问题中的一种)

有一个方法void test() 来测试不同国家的人说的语言,比如说有 Chinese  Japanese French 等几个类,类中都有一个speak() 方法

 然后可以考虑这样写

 void test(Chinese *p)

{

p->speak();

 void test(Japanese*p)

{

p->speak();

 void test(French *p)

{

p->speak();

这样可以达到测试每个对象所说语种的目的。 但这样看起来很不好,这几个函数,只有参数类型不一样,内部实现都一样。那么想  能不能把参数类型设置成某个特殊的类型,这个特殊的类型可以接收 Chinese  Japanese French 等这些类的对象,然后在调用speak时,根据我实际传进去的参数类型,再调用每个类中的speak方法。 如果可以的话就能只写一个函数,实现不同的测试了

void test (special_class *p)

{

p->speak();

}

virtual机制就解决了上述问题,可以弄一个human的基类  然后让Chinese  Japanese French这几个类继承它,  然后语法上允许父类指针指向子类对象

void test(human * p)

{

p->speak();

}

然后问题是 test既然是能处理不同子类对象,那它如何确定该调用哪个子类中的speak()?

这就需要 晚捆绑啊,函数覆盖啊  虚表啊什么的那一套来实现,这个不是我困惑的重点,关于虚表可以看看这个

点击打开链接



第二个  关于晚捆绑

学到这的时候我很是困惑,有早捆绑 或者叫 静态绑定,比如说上边的test 的参数 只是一个类类型  而不是指针或者引用的话,也就是说它没有多态,只能处理一种类型的对象,

这时候调用speak 就是静态绑定,在编译阶段就能完成。   如果有多态  那就叫晚捆绑(动态绑定)  绑定只能在运行时。困惑就在这了,

什么叫运行时才能绑定啊????



在我的程序运行之前,我的所有代码不是已经的写定了么,编译之后 已经生成了 那些固定的汇编语句了啊,还有什么是非得运行之后才确定么????

说是不知道函数要处理的是哪个具体的子类对象,所以确定不了调用哪个函数, 那既然我调用test的代码已经写了

比如     

Chinese  a;

test(a);

那函数要处理的对象不就是Chinese 类型的么   那就能确定调用的是Chinese 中的speak()了

编译时就把p->speak(); 换成 call(Chinese中speak的地址) 不就行了么,还有什么是在运行之前不能确定的呢?????

?????????????????????????????????????????????????????????????????????????????

当时确实很困惑啊,后来想想 too young too naive 啊

按照上边的想法,如果只调用test(a);

那是可以 把test函数中的speak调用改成call(Chinese中speak的地址),当程序执行到test(a);这句时 跳到改好的 test()函数的代码部分  能往下执行,并调用了正确的函数。只要再稍微往后想一点, test()都被改成了 针对对象a的特定版本了, 那还能调用它 来处理其他子类对象么? 不能处理了 ,那多态跑哪去了?

可见照上述我所想的这种静态绑定是实现不了多态的。 那多态是如何实现的,是靠动态绑定实现的,在c++编程思想中讲的比较明白了,为了实现多态,编译器在处理时会隐藏的插入一些内容


简单说,就是因为它不知道要处理的对象类型,不能直接去call某个函数的地址,它插入这段代码,如果是有虚机制的对象,那在对象存储空间里能找到v_ptr  也就是虚表指针,这个不管哪个子类的对象只要有virtual   都会有这个指针,然后通过这个指针的偏移处理,在虚函数表中找到要调用的具体版本的函数的地址,再 call     就能实现不管处理什么类型的子对象,都能找到v_ptr都能通过偏移 找到想要的函数,这就实现了 通用的处理。而这种处理方式,需要在程序运行是,找到传进来的那个具体对象的存储空间,然后在里边找到v_ptr 然后计算等等, 然后才能得到想要的函数, 也就可以理解 这是发生在运行时。



如果对这一块有疑惑,推荐去看c++编程思想第二版  第十五章



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章