天天看點

Effective C++條款33:避免遮掩繼承而來的名稱 實驗示例

隻要成員名稱一樣(即使base classes和derived classes内的函數有不同的參數類型,而且不論函數是vitual或non-virtual),繼承類中的名稱就會遮掩base class内的名稱。

表現如下:

#include<iostream>
using namespace std;
class Base
{
      public:
            void mf1()
             {cout<<"Base::mf1"<<endl;}
            void mf1(int a)
             {cout<<"Base::mf1(int)"<<endl;}
            void mf2()
             {cout<<"Base::mf2"<<endl;} 

};
class Derived:public Base
{
      public:
             void mf1()
             {cout<<"Derived::mf1"<<endl;}
             void mf2()
             {cout<<"Derived::mf2"<<endl;}
             void CallBase()
             {Base::mf1();}
};

int main()
{
    Derived d;
    d.mf1();
    d.CallBase();//正确。如果在類體内通過Base::mf1();則可調用父類的同名函數。
    d.mf1(1);//報錯 no matching function for call to `Derived::mf1(int)'  
             //candidates are: void Derived::mf1() 
    getchar();
}           

在Base中有mf1(int )函數,但是在Derived類中,已經重載了mf1函數,是以把Base中的所有同名函數都遮掩了。隻有mf1()可以通過Derived對象直接調用。

可以Derived類體中直接通過其它函數調用Base中沒有被同名遮掩的成員函數,或者通過Derived對象都可以直接調用Base中沒有被同名遮掩的成員函數。(前提是滿足public\protected\private的繼承限制)。例:

#include<iostream>
using namespace std;
class Base
{
      public:
            void init()
             {cout<<"Base::init"<<endl;}
            void mf1(int a)
             {cout<<"Base::mf1(int)"<<endl;}
            void mf2()
             {cout<<"Base::mf2"<<endl;} 

};
class Derived:public Base
{
      public:
             void CallBase()
             {init();}
};

int main()
{
    Derived d;
    d.CallBase();//正确 
    d.init();//正确 
    getchar();
}           

輸出:

Effective C++條款33:避免遮掩繼承而來的名稱 實驗示例

一個virtual函數的例子:

#include<iostream>
using namespace std;
class Base
{
      public:
            void init()
             {mf1();}
      private:
           virtual void mf1()
             {cout<<"Base::mf1"<<endl;}
};
class Derived:public Base
{
      private:
              virtual void mf1()
              {cout<<"Derived::mf1"<<endl;}
};

int main()
{
    Derived d;
    d.init();//正确
    Base b;
    b.init();
    Base &tb=d;
    tb.init(); 
    getchar();
}           

通過基類的init()通路不同類型的mf1(),實作多态。

如果private繼承則:

#include<iostream>
using namespace std;
class Base
{
      public:
            void init()
             {mf1();}
      private:
           virtual void mf1()
             {cout<<"Base::mf1"<<endl;}
};
class Derived:private Base
{
      private:
              virtual void mf1()
              {cout<<"Derived::mf1"<<endl;}
};

int main()
{
      Derived d;
  //  d.init();//報錯:`void Base::init()' is inaccessible  
             //`Base' is not an accessible base of `Derived' 
    Base b;//正确 
    b.init();//正确 
 //   Base &tb=d;//報錯 `Base' is not an accessible base of `Derived' 
  //  tb.init(); 
  
    getchar();
}
           

上面代碼再變化,把d存到Base b中,造成切割後:

#include<iostream>
using namespace std;
class Base
{
      public:
            void init()
             {mf1();}
      private:
           virtual void mf1()
             {cout<<"Base::mf1"<<endl;}
};
class Derived:public Base
{
      private:
              virtual void mf1()
              {cout<<"Derived::mf1"<<endl;}
};

int main()
{
    Derived d;
    Base b=d;//Derived部分被切割掉了,結果隻剩下基類的mf1可供選擇了。 
    b.init();
    getchar();
}           

結果:

Effective C++條款33:避免遮掩繼承而來的名稱 實驗示例

通過using聲明式讓被遮掩的成員函數重見天日:

#include<iostream>
using namespace std;
class Base
{
      public:
           void mf1()
           {cout<<"Base::mf1"<<endl;}
           void mf1(int x)
           {cout<<"Base::mf1(int)"<<endl;}
};
class Derived:public Base
{
      public:
             using Base::mf1;//這裡用了using 聲明式 
              void mf1()
              {cout<<"Derived::mf1"<<endl;}
};

int main()
{
    Derived d;
    d.mf1();
    d.mf1(1);//有了using Base::mf1 就Derived對象就可以通路基類中被遮掩的同名函數了 
    getchar();
}
           
Effective C++條款33:避免遮掩繼承而來的名稱 實驗示例

通過using聲明式,在Derived類中引入基類被隐藏的函數。

通過轉交函數讓基類中的函數重見天日:

#include<iostream>
using namespace std;
class Base
{
      public:
           void mf1()
           {cout<<"Base::mf1"<<endl;}
           void mf1(int x)
           {cout<<"Base::mf1(int)"<<endl;}
};
class Derived:public Base
{
      public:
              void mf1()
              {Base::mf1();} //轉交 
};

int main()
{
    Derived d;
    d.mf1(); 
    getchar();
}
           

結果:

Effective C++條款33:避免遮掩繼承而來的名稱 實驗示例

個人補充:直接加上作用域符來顯式調用基類同名函數

如:

#include<iostream>
using namespace std;
class A
  {
  public:
       void fun(){cout<<"A::fun"<<endl;}
  };
 
  class B:public A
  {
  public:
      void fun(){cout<<"B::fun"<<endl;}
  };

  void Test()
  {
      B d;
      d.fun();
      d.A::fun();
  }

  int main()
  {
    Test();
    getchar();
    return 0;    
  }
           

結果:

Effective C++條款33:避免遮掩繼承而來的名稱 實驗示例