您的位置:首页 > 编程语言 > C语言/C++

C++与Java中多态实现机制的区别

2017-12-03 18:33 387 查看
一种错误的观点是:c++与java多态性的实现机制不同,但它们的表现形式应该相同。以下我将举出两个例子(请耐心看)。

class Super {
public Super() {
init();
}
protected void init() {
System.out.print("1:Super");
}
}
public class Sub extends Super{
public Sub(){
init();
}
public void init() {
System.out.print("2:Sub");
}
public static void main(String[] args)
{
Super test=new Sub();
// 输出
// 2:Sub 2:Sub
}
}


如果换成C++相信大家都知道会输出 1:Super 2:Sub

1. C++中的函数调用方式

普通函数调用:具体调用哪个方法在编译时间就可以决定(通过查找编译器的符号表),同时在使用标准过程调用机制基础上增加一个表示对象身份的指针(this指针)。

虚函数调用:函数调用依赖于对象的实际类型,一般地说,对象的实际类型只能在运行时间才能确定。虚函数一般要有两个步骤来支持,首先每一个类产生出一堆指向虚函数的指针,放在表格中,这个表格就叫虚函数表(virtual table);然后每一个类对象(class object)会添加一个指向相关虚函数表(virtual table)的指针,通常这个指针叫做vptr(自己动手写几个虚函数试试,检查class的size ,会发现明显变大。C++中Vptr放在每个对象实例内存最开始的位置)。

2. Java中的函数调用方式

在java虚拟机中,类实例的引用(实例对象名)就是指向一个句柄(handle)的指针,而该句柄其实是一对指针:其中一个指针指向一张表,该表格包含了对象的方法列表以及一个指向类对象(表示对象类型)的指针;另一个指针指向一块内存地址,该内存是从java堆中为对象的数据而分配出来的。

现在回到我们刚才的例子,java中的类对象在构造前(调用构造函数之前)就已经存在了,其函数表和对象类型也已经确定了,就是说还没有出生就已经存在了。

而C++中只有在构造完毕后(所有的构造函数都被成功调用)才存在,其函数表和对象的实际类型才会确定。所以这两个例子的执行结果会不一样。(个人的猜测是先构建父类对象,所以此时虚函数指针指向的是父类的虚函数,当构建子类时,虚函数指针被覆盖为子类虚函数,每一层构造都完成后,虚函数指针才被确定)

从这个例子,我们可以看出这样一个陷阱——java例子中按照逻辑应该执行的初始化函数,没有执行,即父类的初始化函数没有得到执行,这点在写代码是要注意规避。

最后讲讲java中,属性与方法的隐藏与覆盖的例子。

package Temp;

class Parent{

int x=10;
public Parent(){
System.out.println("1:" + x);
add(2);
System.out.println("2:" + x);
}
void add(int y){
System.out.println("3:" + x);
x+=y;
System.out.println("4:" + x);
}
}

class Child extends Parent{
int x=9;
void add(int y){
System.out.println("5:" + x);
x+=y;
System.out.println("6:" + x);
}
public static void main(String[] args){
Parent p=new Child();
System.out.println(p.x);
}
}


输出为:

1:10

5:0

6:2

2:10

10

有兴趣可以研究为什么这样。

本文是我在看了这篇文章后的总结。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: