C++/Java中继承关系引发的调用关系详解
2015-09-08 18:27
453 查看
C++:
这里引用到了 http://blog.csdn.net/haoel/article/details/1948051/ 中的内容,还请提前阅读陈大神的这篇博客后在阅读本篇。
覆盖,实现多态的基础,通过虚函数表来实现,下面这个例子便是覆盖 Override
如果 Base类f()没有被virtual修饰,如下
如果理解了陈大神博客上那些图,应该不会对这个结果产生意外,这是我画的一个草图,并不对应于真实的内存地址情况,只是为了方便说明概念,下面一排描述的是Derived:
解析:首先p是Base类型的指针,其对于p而言其能只能按照Base类型去运算偏移地址等来访问,所以其不可能访问到Derived中的函数。也就是说父类指针的作用域只有int a , Base::f Base::g这一部分。这样就能理解了。
隐藏,父类指针的访问域是父类部分,子类虽然拥有一份父类函数的拷贝,但如果子类中存在于父类同名的函数,则调用和变量类型一致的函数(即父类变量调用父类函数,子类变量调用子类函数,同时成对方的函数被隐藏)。例:
这里虽然传入f的参数是float型,更适合调用Base::f,但根据同名优先调用子类的原则,实际调用为Derived::f。这就是父类同名方法被隐藏,如果指针类型为父类,则称子类方法被隐藏。
如果子类f定义为 void f() 这里对f传值就会编译不通过。
Java
覆盖,java的情况很简单,只要是子类含有和父类的同名方法,就是覆盖(无论子类的函数是否为abstract)。
隐藏,Java中也存在隐藏,不过这个隐藏和C++不太一样,子类对象引用可以调用父类的同名函数
再讲覆盖,C++父类函数中如果调用了自己的虚成员函数,那么由于这个虚成员函数被覆盖了,所以其实相当于调用了子类的函数。例:
Java中类似:
由于想利用这种特性,有人会犯一个错误,在父类的构造函数中调用被覆盖的函数,由于子类在构建时先调用父类的构造函数,此时子类为构造所以不能调到子类的覆盖方法,由此
产生了奇怪的错误。
这里引用到了 http://blog.csdn.net/haoel/article/details/1948051/ 中的内容,还请提前阅读陈大神的这篇博客后在阅读本篇。
覆盖,实现多态的基础,通过虚函数表来实现,下面这个例子便是覆盖 Override
#include<iostream> using namespace std; class Base{ public: Base(){ cout << "Base::Base" << endl; } virtual void f(){ cout << "Base::f" << endl; } }; class Derived : public Base{ public: Derived(){ cout << "Devried::Derived" << endl; } void f(){ cout << "Derived::f" << endl; } }; int main(){ Base *p = new Derived(); // Base::Base CRCL Derived::Derived p->f(); // Derived::f }
如果 Base类f()没有被virtual修饰,如下
#include<iostream> using namespace std; class Base{ public: Base(){ cout << "Base::Base" << endl; } void f(){ cout << "Base::f" << endl; } }; class Derived : public Base{ public: Derived(){ cout << "Devried::Derived" << endl; } void f(){ cout << "Derived::f" << endl; } }; int main(){ Base *p = new Derived(); p->f(); // Base::f }
如果理解了陈大神博客上那些图,应该不会对这个结果产生意外,这是我画的一个草图,并不对应于真实的内存地址情况,只是为了方便说明概念,下面一排描述的是Derived:
解析:首先p是Base类型的指针,其对于p而言其能只能按照Base类型去运算偏移地址等来访问,所以其不可能访问到Derived中的函数。也就是说父类指针的作用域只有int a , Base::f Base::g这一部分。这样就能理解了。
隐藏,父类指针的访问域是父类部分,子类虽然拥有一份父类函数的拷贝,但如果子类中存在于父类同名的函数,则调用和变量类型一致的函数(即父类变量调用父类函数,子类变量调用子类函数,同时成对方的函数被隐藏)。例:
#include<iostream> using namespace std; class Base{ public: int a; Base(){ cout << "Base::Base" << endl; } void f(float a){ cout << "Base::f" << endl; } }; class Derived : public Base{ public: int d; Derived(){ cout << "Devried::Derived" << endl; } void f(int a){ cout << "Derived::f" << endl; } }; int main(){ Derived *p = new Derived(); p->f(3.14f); // Derived::f }
这里虽然传入f的参数是float型,更适合调用Base::f,但根据同名优先调用子类的原则,实际调用为Derived::f。这就是父类同名方法被隐藏,如果指针类型为父类,则称子类方法被隐藏。
如果子类f定义为 void f() 这里对f传值就会编译不通过。
Java
覆盖,java的情况很简单,只要是子类含有和父类的同名方法,就是覆盖(无论子类的函数是否为abstract)。
public class Test { public static void main(String[] args){ Base base = new Derived(); base.f(); // Derived::f } } class Base { public void f() { System.out.println("Base::f"); } } class Derived extends Base { public void f() { System.out.println("Derived::f"); } }
隐藏,Java中也存在隐藏,不过这个隐藏和C++不太一样,子类对象引用可以调用父类的同名函数
public class Test { public static void main(String[] args){ Derived derived = new Derived(); derived.f(3); //Derived::f derived.f(3.14f); // Base::f } } class Base { public void f(float a) { System.out.println("Base::f"); } } class Derived extends Base { public void f(int a) { System.out.println("Derived::f"); } }
再讲覆盖,C++父类函数中如果调用了自己的虚成员函数,那么由于这个虚成员函数被覆盖了,所以其实相当于调用了子类的函数。例:
#include<iostream> using namespace std; class Base{ public: int a; Base(){ cout << "Base::Base" << endl; } void f(){ g(); } virtual void g(){ cout << "Base::g" << endl; } }; class Derived : public Base{ public: int d; Derived(){ cout << "Devried::Derived" << endl; } void g(){ cout << "Derived::g" << endl; } }; int main(){ Derived *p = new Derived(); p->f(); // Derived::g }
Java中类似:
public class Test { public static void main(String[] args){ Base base = new Derived(); base.f(); //Derived::f } } class Base { public void f() { g(); } public void g(){ System.out.println("Base::g"); } } class Derived extends Base { public void g(){ System.out.println("Derived::g"); } }
由于想利用这种特性,有人会犯一个错误,在父类的构造函数中调用被覆盖的函数,由于子类在构建时先调用父类的构造函数,此时子类为构造所以不能调到子类的覆盖方法,由此
产生了奇怪的错误。
相关文章推荐
- 可调用对象与function
- const在函数前与函数后的区别
- C++设计模式--单例、策略模式
- 算法—判断整数序列是不是二元查找树的后序遍历结果
- c++复制函数的区别
- C++ 插入排序并统计数值出现的次数
- C/C++ 编写一个通用的Makefile 来编译.c .cpp 或混编
- c++ 解析eps文件
- C++宏定义详解
- c++ int转换为枚举类型
- C++_string_basic_string::c_str() 与 basic_string::data() 区别
- 【面试算法系列】已知二叉树的前序和中序遍历重建二叉树 - C语言实现
- 确定public继承出来的是Is_a关系(Effective C++_32)
- leetcode--Find Minimum in Rotated Sorted Array II ---C++
- C语言中常用的库函数
- 大数相乘的实现
- C++ 基本知识
- C++ 强制类型转换
- C++ 抽象类
- C++ 中指针与引用的区别