之前一直用C++编程,对虚函数还是一些较为肤浅的理解。可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题。
Java中的虚函数
以下是段别人的代码,输入结果竟是Base,这让一直以来用C/C++的我有些莫不着头脑,不是Java里对象是引用吗?C/C++中通过指向基类的指针或引用来指向派生类,那么对于虚函数来说通过基类指针使用的是指向的派生类。但在Java中没有keyword标明虚函数,此时就不是非常明确究竟调用的谁。
class base { private void print() { System.out.println("base"); } public void doprint() { print(); } } class derive extends base { private void print() { System.out.println("derive"); } } class testVirtual { public static void main(String args[]) { base b = new derive(); b.doprint(); } }
而以下这段Java输出的是derived,注意函数以及訪问权限的变化。
class base { public void print() { System.out.println("base"); } public void doprint() { print(); } } class derive extends base { public void print() { System.out.println("derive"); } } class testVirtual { public static void main(String args[]) { base b = new derive(); b.print(); } }
大牛甲如是说:“java里的protected,public,包訪问级别的函数都是虚函数。”也有大牛乙如是说:“java里的都是虚函数。”我的解读是这二位大牛的话肯定都对,private级别的函数也能够说是虚函数,仅仅只是基类的引用无法直接訪问派生类的private级别的函数罢了,仅仅能訪问自己的。
于是能够断定以下这段就是输出derive了。没错,就是这样。
class base { private void print() { System.out.println("base"); } public void doprint() { print(); } } class derive extends base { private void print() { System.out.println("derive"); } public void doprint() { print(); } } class testVirtual { public static void main(String args[]) { base b = new derive(); b.doprint(); } }
C++中的虚函数
以下这段C++代码输出的是drived,通过基类的指针或引用指向派生类或基类,然后调用二者共同拥有都有的作为虚函数的函数,此时调用的是指针所指向的类(能够是基类也能够是派生类,关键看此时基类的指针或引用指向的是派生类还是基类)。注意仅仅有基类的指针或引用才干实现虚函数有关多态的问题,其它类型在C++中仅仅调用自己的函数。
#include<iostream> using namespace std; class base { private: virtual void print() { printf("base\n"); } public: void doprint() { print(); } virtual ~base(){} }; class derived : public base { virtual void print() { printf("derived\n"); } }; int main(int argc, char* argv[]) { derived d; base& b = d; b.doprint(); return 0; } //也是derived #include<iostream> using namespace std; class base { private: virtual void print() { printf("base\n"); } public: void doprint() { print(); } virtual ~base(){} }; class derived : public base { private: virtual void print() { printf("derived\n"); } public: void doprint() { print(); } }; int main(int argc, char* argv[]) { derived d; base& b = d; b.doprint(); return 0; } //输出的是base #include<iostream> using namespace std; class base { private: virtual void print() { printf("base\n"); } public: void doprint() { print(); } virtual ~base(){} }; class derived : public base { private: virtual void print() { printf("derived\n"); } public: void doprint() { print(); } }; int main(int argc, char* argv[]) { derived d; base b = d; b.doprint(); return 0; }
以下这段输出的就是base了,由于不是虚函数,通过基类的指针或引用调用的就是基类的函数。
#include<iostream> using namespace std; class base { public: void print() { printf("base\n"); } virtual ~base(){} }; class derived : public base { public: void print() { printf("derived\n"); } }; int main(int argc, char* argv[]) { derived d; base& b = d; b.print(); return 0; }
以下C++代码输出的是derived,这就是同名覆盖原则,派生类覆盖积累的同名函数。
#include<iostream> using namespace std; class base { public: void print() { printf("base\n"); } virtual ~base(){} }; class derived : public base { public: void print() { printf("derived\n"); } }; int main(int argc, char* argv[]) { derived d; base& b = d; d.print(); return 0; }
总结对照
C++
Java
虚函数 -------- 普通函数
纯虚函数 -------- 抽象函数
抽象类
-------- 抽象类
虚基类
-------- 接口
关于虚函数的实现机制,涉及虚函数表等,兴许博客补上。因为理论知识不足,难以上升到详细底层实现,望理解!