• c++中的重载(Overload)、覆盖(重写,Override) 、隐藏与访问权限控制及using声明


    这些概念有时记住了,但可能没多久就忘了,还是记下来吧。网上找的一篇不错:这里

     1 重载与覆盖

        成员函数被重载的特征:

    (1)相同的范围(在同一个类中,不包括继承来的);

    (2)函数名字相同;

    (3)参数不同;(包括const和非const,这里const既指形参,也指函数本身)

    //《C++ primer》中提到“仅当形参是引用或指针的时候,形参是否为const才对重载有影响。”
    void f(int a);
    void f(const int a);//error:重复定义
    
    //引用或指针所指为const时ok。指针常量不可以。
    void f(int *p);
    void f(const int *p);//ok
    void f(int *const p);//error:重复定义
    
    //调用含const形参引用的函数时,若实参类型与形参不匹配(如非const变量),将尽可能做类型转换,并产生临时变量存储实参转换后的值。并把形参作为该对象的引用!!-->c++11转移构造和转移赋值函数可解 -- 右值引用
    
    因此下面均为重载:
    class A
    {
    public:
       void f(int *);
       void f(const int *);
       void f(int *) const;//因为隐含的this指针类型为const A*   
    };

    (4)virtual关键字可有可无。 

        覆盖是指派生类函数覆盖基类函数,特征是:

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

    (2)函数名字相同;

    (3)参数相同;

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

    令人迷惑的隐藏规则
    本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性陡然增加。这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
    (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
    (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

    例:

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
        virtual void vf(float x){ cout << "Base::f(float) " << x << endl; }
    
        void foo(){ cout << "Base::foo() " << endl; }
        virtual void g(float x){ cout << "Base::g(float) " << x << endl; }
        void h(float x){ cout << "Base::h(float) " << x << endl; }
    }; 
    
     
    class Derived : public Base
    {
    public:
        virtual void vf(float x){ cout << "Derived::f(float) " << x << endl; }
        
        void foo(int x){ cout << "Base::foo() " << x << endl; }
        void g(int x){ cout << "Derived::g(int) " << x << endl; } //隐藏-因为参数不同--即使基类函数是virtual
        void h(float x){ cout << "Derived::h(float) " << x << endl; }//隐藏-即使参数相同,但非virtual
    };
    
    void main(void)
    {
        Derived d;
        Base *pb = &d;
        Derived *pd = &d;
        // 多态 --- 取决于指向的对象类型
        pb->vf(3.14f); // Derived::f(float) 3.14
        pd->vf(3.14f); // Derived::f(float) 3.14
    
        // 取决于指针类型
        pb->foo(); //Base::foo()
        //pd->foo(); //编译出错,派生类隐藏了Base::foo()
        pb->g(3.14f); // Base::g(float) 3.14
        pd->g(3.14f); // Derived::g(int) 3   -->隐式转换
    
        // 取决于指针类型
        pb->h(3.14f); // Base::h(float) 3.14
        pd->h(3.14f); // Derived::h(float) 3.14
    }

    上面的程序中:

    (1)函数Derived::f(float)覆盖了Base::f(float)。
    (2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
    (3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。

     基类中被隐藏的函数可用作用域标识符直接调用,当然,在类外::只可访问public成员

    pd->Base::foo();
    pd->Base::g(3.14f);
    pd->Base::h(3.14f);

    当然,也可在类定义内部使用Base::foo();等等(派生类内(不管private继承还是protected继承)::可访问基类的public protected成员,但不能访问private函数)---这叫转发函数

    也可以在派生类定义时使用using声明

    class Derived : public Base
    {
    public:
      //让基类中所有名为 foo 和 g 的东西(如函数名 变量)在Derived的作用域中可见(并且是公有的)
      using Base::foo;
      using Base::g;    
      ...  
    }

    这样,之前对 pd->foo(); 等的调用都能成功

    注意。不管如何继承,基类的私有成员都将在派生类中变的no access, using声明也无法使用基类的私有成员。关于继承级别和访问级别的权限控制,见这篇文章

    using的作用域问题与继承时访问标号的关系,可见:派生类中用using声明改变基类成员的访问权限

  • 相关阅读:
    基于Lucene 4.x的ikanalyzer
    scala实现HighCharts生成的SVG图像下载
    使用solrj和EasyNet.Solr进行原子更新
    Bootstrap 2.3.0自定Grid布局
    无法删除打印机Failed to remove driver ZDesigner ZT210300dpi ZPL. Failed to remove package zdesigner.inf. Driver package is in use.
    彩云披月镜,委蛇藏花芯。朝辞浮云晓,元初破日衣。
    python browser.find_element_by 方法过期browser.find_element_by_tag_name;browser.find_element_by_class_name;browser.find_element_by_id;browser.find_element_by_name;
    c++中按位取反
    typedef用法总结
    Visual C++开发工具与调试技巧整理
  • 原文地址:https://www.cnblogs.com/sfqtsh/p/5148713.html
Copyright © 2020-2023  润新知