java继承的调用关系_C++/Java中继承关系引发的调用关系详解

C++:

覆盖,实现多态的基础,通过虚函数表来实现,下面这个例子便是覆盖 Override

1 #include

2

3 using namespacestd;4

5 classBase{6 public:7 Base(){8 cout << "Base::Base" <

11 virtual voidf(){12 cout << "Base::f" <

16 class Derived : publicBase{17 public:18 Derived(){19 cout << "Devried::Derived" <

22 voidf(){23 cout << "Derived::f" <

27 intmain(){28 Base *p = newDerived(); // Base::Base CRCL Derived::Derived29 p->f(); // Derived::f30 }

如果 Base类f()没有被virtual修饰,如下

1 #include

2

3 using namespacestd;4

5 classBase{6 public:7 Base(){8 cout << "Base::Base" <

11 voidf(){12 cout << "Base::f" <

16 class Derived : publicBase{17 public:18 Derived(){19 cout << "Devried::Derived" <

22 voidf(){23 cout << "Derived::f" <

27 intmain(){28 Base *p = newDerived();29 p->f(); // Base::f30 }

如果理解了陈大神博客上那些图,应该不会对这个结果产生意外,这是我画的一个草图,并不对应于真实的内存地址情况,只是为了方便说明概念,下面一排描述的是Derived:

0202c05eb05774d2456efee449a6be2c.png

解析:首先p是Base类型的指针,其对于p而言其能只能按照Base类型去运算偏移地址等来访问,所以其不可能访问到Derived中的函数。也就是说父类指针的作用域只有int a , Base::f Base::g这一部分。这样就能理解了。

隐藏,父类指针的访问域是父类部分,子类虽然拥有一份父类函数的拷贝,但如果子类中存在于父类同名的函数,则调用和变量类型一致的函数(即父类变量调用父类函数,子类变量调用子类函数,同时成对方的函数被隐藏)。例:

1 #include

2

3 using namespacestd;4

5 classBase{6

7 public:8 inta;9

10 Base(){11 cout << "Base::Base" <

14 void f(floata){15 cout << "Base::f" <

19 class Derived : publicBase{20 public:21 intd;22 Derived(){23 cout << "Devried::Derived" <

26 void f(inta){27 cout << "Derived::f" <

31 intmain(){32 Derived *p = newDerived();33 p->f(3.14f); // Derived::f34 }

这里虽然传入f的参数是float型,更适合调用Base::f,但根据同名优先调用子类的原则,实际调用为Derived::f。这就是父类同名方法被隐藏,如果指针类型为父类,则称子类方法被隐藏。

如果子类f定义为 void f() 这里对f传值就会编译不通过。

Java

覆盖,java的情况很简单,只要是子类含有和父类的同名方法,就是覆盖(无论子类的函数是否为abstract)。

public classTest {public static voidmain(String[] args){

Basebase = newDerived();base.f(); // Derived::f

}

}classBase {public voidf() {

System.out.println("Base::f");

}

}classDerived extends Base {public voidf() {

System.out.println("Derived::f");

}

}

隐藏,Java中也存在隐藏,不过这个隐藏和C++不太一样,子类对象引用可以调用父类的同名函数

1 public classTest {2 public static voidmain(String[] args){3 Derived derived = newDerived();4 derived.f(3); //Derived::f5 derived.f(3.14f); // Base::f6 }7 }8

9 classBase {10

11 public void f(floata) {12 System.out.println("Base::f");13 }14 }15

16 classDerived extends Base {17 public void f(inta) {18 System.out.println("Derived::f");19 }20 }

再讲覆盖,C++父类函数中如果调用了自己的虚成员函数,那么由于这个虚成员函数被覆盖了,所以其实相当于调用了子类的函数。例:

#include

using namespacestd;classBase{public:inta;

Base(){

cout<< "Base::Base" <

}voidf(){

g();

}virtual voidg(){

cout<< "Base::g" <

}

};class Derived : publicBase{public:intd;

Derived(){

cout<< "Devried::Derived" <

}voidg(){

cout<< "Derived::g" <

}

};intmain(){

Derived*p = newDerived();

p->f(); // Derived::g

}

Java中类似:

1 public classTest {2 public static voidmain(String[] args){3 Base base = newDerived();4 base.f(); //Derived::f5 }6 }7

8 classBase {9

10 public voidf() {11 g();12 }13

14 public voidg(){15 System.out.println("Base::g");16 }17 }18

19 classDerived extends Base {20 public voidg(){21 System.out.println("Derived::g");22 }23 }

由于想利用这种特性,有人会犯一个错误,在父类的构造函数中调用被覆盖的函数,由于子类在构建时先调用父类的构造函数,此时子类为构造所以不能调到子类的覆盖方法,由此

产生了奇怪的错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值