zoukankan      html  css  js  c++  java
  • C++的重写(覆盖)、重载、重定义(隐藏)、多态

    “重写(覆盖)、重载、重定义、多态” 绝对称得上是C++里一个比较经典的问题了,下面我们来层层剖析它。


    重写(覆盖)override

    重写又名覆盖,常见于子类继承父类的时候,子类重写父类的某些方法。
    有如下要求:

    • 父类中被重写的方法必须是virtual的
    • 子类中进行重写操作的那个方法,访问修饰符和父类的可以不同(即根据自身需要选择public、protected、private), 但是返回值、参数列表(参数的顺序、类型)和父类必须相同。

    下面是一个重写的例子:

    class B
    {
    private:
        virtual void f(int i, char c)
        {
            cout<<"BBB"<<endl;
        }
    };
    
    class A:B
    {
    public:
        void f(int j, char ch)
        {
            cout<<"AAA"<<endl;
        }
    };
    
    int main()
    {
        A a;
        a.f(2,'a');
        return 0;
    }
    

    输出为:AAA


    重载 overload

    重载是指对同一个名称的函数,根据其参数的不同可以执行不同的操作。
    举个栗子,下面的几种函数都属于重载,他们的要求就是参数表(参数个数、参数类型、参数顺序)必须至少要有一点不同!

    inf f(){...}
    int f(int a){...}
    int f(char a){...}
    int f(int a, char b){...}
    ....
    

    注意啦,重载强调的是参数表要不同,而如果只改变返回值的类型的话则不属于重载,编译时会报错。比如如下的代码则不算是重载:

    int f(){...}
    void f(){...}
    

    这个例子中编译会报:error: 'void A::f()' cannot be overloaded

    重载还有一个地方需要注意,就是重载很容易产生二义性。
    比如:

    int f(int a){...}
    int f(double a){...}
    

    当你执行f(2)的时候,编译器不知道你要执行的是哪一个函数,这个时候的调用办法如下:

    f((int) 2);			// 调用第一个函数
    f((double) 2);	// 调用第二个函数
    

    重载还可以用来重载运算符,这里就不作细致讨论了。


    重定义(隐藏) redefining

    重定义又称隐藏,它也常见于子类继承父类的情况中,注意区分重定义和重写的区别。
    重定义是子类中有一个和父类方法名一样的方法,且父类中那个方法不能被virtual修饰,而且子类和父类中这个方法的参数表可以不同。

    class A
    {
    public:
        void f()
        {
            cout<<"AAA"<<endl;
        }
    
    };
    
    class B:public A        // 这里必须是public或者protected,否则子类访问不了父类的方法
    {
    public:
        void f(int i)
        {
            cout<<i<<endl;
        }
    };
    
    int main()
    {
        B b;
        // b.f(); 编译错误,父类方法已被隐藏
        b.A::f();      // 想访问父类方法,只能这样
        b.f(2);     // 这里是调用B类的方法
        return 0;
    }
    
    

    多态 polymorphism

    多态是基于重写的,因此基类方法必须加virtual。
    我们都知道父类指针可以指向子类对象,而多态就是用于给父类指针调用子类重写后的的方法的。
    举个例子就明白了:

    class A
    {
    public:
        void f()    // 非多态
        {
            cout<<"A-f()"<<endl;
        }
        virtual void g()    // 多态
        {
            cout<<"A-g()"<<endl;
        }
    
    
    };
    
    class B:public A
    {
    public:
        void f()
        {
            cout<<"B-f()"<<endl;
        }
        void g()
        {
            cout<<"B-g()"<<endl;
        }
    };
    
    int main()
    {
        B b;
        A *a = &b;
        a->f();     // 没有多态,输出为:A-f()
        a->g();     // 有多态,输出为:B-g()
    
        return 0;
    }
    

    总结

    • 重写要求基类方法前加上virtual,且返回值及参数列表均需和基类相同。
    • 重载要求参数列表和原函数不同,仅有返回值不同不算重载,使用时需要注意二义性。
    • 重定义要求方法名和父类相同,其余可以不同,且此时要调用父类方法时只能采用::来调用
    • 多态是基于重写的一种程序调用方法,当基类的指针指向子类对象时可以调用子类的方法。
  • 相关阅读:
    openwrt的内核版本是在哪个文件中指定的?
    git如何将一个分支合并到另一个分支?
    cygwin如何下编译安装tmux?
    如何合并ts文件?
    在cygwin下创建的文件位于windows的哪个目录下?
    linux shell的for循环语法是怎样的?
    内部类访问局部变量时,为什么需要加final关键字
    Java8函数式编程的宏观总结
    Maven私服使用经验总结
    java关于Integer设置-128到127的静态缓存
  • 原文地址:https://www.cnblogs.com/yinyoupoet/p/13287450.html
Copyright © 2011-2022 走看看