关于Java与c++隐藏、重写不同实现机制的探讨

一、文章来由

本人现在用c++更多,但是以前Java也写过不少,Java和c++很像,但是深入挖一些,Java跟c++的区别很大,就拿刚刚发的另一篇博文虚函数与多态小览来说,里面就感觉有很多不同了,至少“重写”在这两个语言里面的理解就不同了~~跟基友一番讨论,决定把这个问题彻底捋一捋,因为这个是探讨,所以有不同想法欢迎提出和评论。

二、关于“重写”Override的定义

“重写”多么常见的一个概念。

1、首先说明“重写”(Override)完全等于“覆盖”,可能因为翻译的问题,是个很坑爹的问题

2、而且 Override 的定义在c++和Java中却不同~~

c++中这样定义“重写”:

Override 是指派生类函数覆盖基类函数:

(1)不同的范围(分别位于派生类与基类);

(2)函数名字相同;

(3)参数相同,参数不同都不称之为重写,根本就是两个函数了;

(4)基类函数必须有virtual 关键字

特别留意最后一点~~这是区别于隐藏的关键点

Java中这样定义“重写”:

(1)在子类中可以根据需要对从基类中继承来的方法进行重写,方法重写又称方法覆盖。

(2)重写的方法和被重写的方法必须具有相同方法名称、参数列表和返回类型。

(3)重写方法不能使用比被重写的方法更严格的访问权限。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。

有没有发现什么,就是Java中根本没有virtual关键字,所以没有“重写”和“隐藏”的区别,Java中重写一定隐藏了父类的方法,要访问就要用super关键字就可以了,所以Java里面只有 override。

三、深入理解c++中的 Hidden 与 Override

看了定义就已经发现不同了,现在来自己看看c++中 Hidden 与 override 的实现机制。

谈到c++的 override 就一定要谈到 hidden,他们在c++中是要绝对区分开的。

3.1 Hidden

c++隐藏的定义(派生类的函数屏蔽了与其同名的基类函数):

(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)

(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

这是上一篇博客也提到的类容,那么究竟实现机制是什么?

在调用一个类的成员函数的时候,编译器会沿着类的继承链逐级的向上查找函数的定义,如果找到了那么就停止查找了,所以如果一个派生类和一个基类都有同一个同名(暂且不论参数是否相同)的函数,而编译器最终选择了在派生类中的函数,那么我们就说这个派生类的成员函数”隐藏”了基类的成员函数,也就是说它阻止了编译器继续向上查找函数的定义。。。。

回到隐藏的定义中,前面已经说了有virtual关键字并且分别位于派生类和基类的同名,同参数函数构成覆盖的关系,因此隐藏的关系只有如下的可能:

1)必须分别位于派生类和基类中

2)必须同名

3)参数不同的时候本身已经不构成覆盖关系了,所以此时是否是virtual函数已经不重要了

当参数相同的时候就要看时候有virtual关键字了,有的话就是覆盖关系,没有的时候就是隐藏关系了

3.2 Override

覆盖指的是派生类的虚拟函数覆盖了基类的同名且参数相同的函数。

既然是和虚拟函数挂钩,说明了这个是一个多态支持的特性,所谓的覆盖指的是用基类对象的指针或者引用时访问虚拟函数的时候会根据实际的类型决定所调用的函数,因此此时派生类的成员函数可以”覆盖”掉基类的成员函数。

注意: 唯有同名参数相同还有带有virtual关键字并且分别在派生类和基类的函数才能构成虚拟函数,这个也是派生类的重要特征。

而且,由于是和多态挂钩的,所以只有在使用类对象指针或者引用的时候才能使用上。

总之一句话:覆盖函数都是虚函数,反之不然~~

四、代码实例

口说无凭,上代码~~

Java代码如下:

public class PolyTest
{
    public static void main(String[] args)
    {

        //向上类型转换
        Cat cat = new Cat();
        Animal animal = cat;
        animal.sing();

        //向下类型转换
        Animal a = new Cat();
        Cat c = (Cat)a;
        c.sing();
        c.eat();

        //编译错误
        //用父类引用调用父类不存在的方法
        //Animal a1 = new Cat();
        //a1.eat();

        //编译错误
        //向下类型转换时只能转向指向的对象类型
        //Animal a2 = new Cat();
        //Cat c2 = (Dog)a2;

    }
}

class Animal
{
    public void sing()
    {
        System.out.println("Animal is singing!");
    }
}

class Dog extends Animal
{
    public void sing()
    {
        System.out.println("Dog is singing!");
    }
}

class Cat extends Animal
{
    public void sing()
    {
        System.out.println("Cat is singing!");
    }
    public void eat()
    {
        System.out.println("Cat is eating!");
    }
}

跑出来结果如下:

可见,Java即便第二组向下转换【父类强转子类】,输出任然是子类的东西,并不像c++的晚绑定。

c++代码如下:

#include<iostream>
using namespace std;

class Animal
{
public:
    virtual void sing()
    {
        printf("Animal is singing!\n");
    }
};

class Cat : public Animal
{
public:
    void sing()
    {
        printf("Cat is singing!\n");
    }

    void eat()
    {
        printf("Cat is eating!\n");
    }
};

int main(void)
{
    Animal a;
    Cat *cp = (Cat *)&a;
    cp->sing();
    cp->eat();

    //编译错误
//  Cat c;
//  Animal a = c;
//  a.eat();

    return 0;
}

运行结果如下:

c++这里就良好体现了晚绑定的特性~~~即使强制转换了,指向的任然是基类对象的地址,所以通过虚函数列表还是可以找到基类的实现~

五、小结

Java与c++在隐藏、重写的不同就介绍到这里,刚刚在线Markdown没有保存,就打开了上一篇的编辑,差点以为要冲掉这篇了,码了好多字啊,吓傻了。。。看来以后要多导入到本地~~哈哈哈

—END—


参考文献

[1] http://bbs.chinaunix.net/thread-643467-1-1.html

[2] http://www.cnblogs.com/mengdd/archive/2012/12/25/2832288.html

版权声明:欢迎转载,注明出处就好!如果不喜欢请留言说明原因再踩哦,谢谢,我也可以知道原因,不断进步!!

时间: 2024-10-21 16:28:04

关于Java与c++隐藏、重写不同实现机制的探讨的相关文章

Java中的方法重写 与 final关键字

Java中的方法重写 与 final关键字 以下程序是否存在错误? class Base { private final void method() { System.out.println("In Base..."); } } class Sub extends Base { public void method() { System.out.println("In Sub..."); } } 答案 正确的. 使用final关键字可以声明类.成员变量和成员方法,一

java中重载与重写浅析

java中重载与重写浅析 Overloading (1) 方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型. 重载Overloading是一个类中多态性的一种表现. (2) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义. 调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性. (3) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以

左右JAVA示例代码事件分发和监督机制来实现-绝对原创有用

文章标题:左右JAVA示例代码事件分发和监督机制来实现 文章地址: http://blog.csdn.net/5iasp/article/details/37054171 作者: javaboy2012Email:[email protected]qq:    1046011462 一.场景如果 如果有博客系统中须要实现例如以下功能: 系统中用户公布文章.改动文章.删除文章时,须要一些相关的操作须要运行. 公布文章后,给好友发送邮件通知.给用户加积分,对文章做全文索引. 改动文章后,给好友发送邮

【Java深入研究】6、fail-fast机制

转自:http://blog.csdn.net/chenssy/article/details/38151189 在JDK的Collection中我们时常会看到类似于这样的话: 例如,ArrayList: 注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证.快速失败迭代器会尽最大努力抛出 ConcurrentModificationException.因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该

4.JAVA之GUI编程事件监听机制

事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件.(如:鼠标单击事件) 监听器:将可以触发某一事件的动作(不止一个动作)都已经封装到了监听器中. 以上三者,在java中都已经定义好了,直接获取其对象来用就可以了. 我们要做的事情是,就是对产生的动作进行处理. 图解事件监听机制: 4.JAVA之GUI编程事件监听机制,布布扣,bubuko.com

Java中内存泄露及垃圾回收机制

3 垃圾回收机制 3.1 什么是垃圾 垃圾,内存中的垃圾,即内存中已无效但又无法自动释放的空间.在Java语言中,没有引用句柄指向的类对象最容易成为垃圾.,产生垃圾的情况有很多,主要有以下3种: (1)       超出对象的引用句柄的作用域时,这个引用句柄引用的对象就变成垃圾. 例: { Person p1 = new Person(); …… } 引用句柄p1的作用域是从定义到“}”处,执行完这对大括号中的所有代码后,产生的Person对象就会变成垃圾,因为引用这个对象的句柄p1已超过其作用

关于JAVA中事件分发和监听机制实现的代码实例-绝对原创实用

http://blog.csdn.net/5iasp/article/details/37054171 文章标题:关于JAVA中事件分发和监听机制实现的代码实例 文章地址: http://blog.csdn.net/5iasp/article/details/37054171 作者: javaboy2012Email:[email protected]qq:    1046011462 一.场景假设 假设有博客系统中需要实现如下功能: 系统中用户发布文章,修改文章,删除文章时,需要一些相关的操作

Java提高篇(三四)-----fail-fast机制

在JDK的Collection中我们时常会看到类似于这样的话: 例如,ArrayList: 注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证.快速失败迭代器会尽最大努力抛出 ConcurrentModificationException.因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug. HashMap中: 注意,迭代器的快速失败行为不能得到保证,一般来说,存在非同步的并发修改时

深入java虚拟机学习 -- 类的加载机制(续)

昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: class Singleton { private static Singleton singleton = new Singleton(); //第一份代码的位置 public static int counter1; public static int counter2=0; private s