Effective C++条款33:避免遮掩继承而来的名称 实验示例

64 篇文章 0 订阅
1 篇文章 0 订阅

只要成员名称一样(即使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();
}
输出:


一个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();
}
结果:



通过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();
}

通过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();
}
结果:


个人补充:直接加上作用域符来显式调用基类同名函数

如:

#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;    
  }
结果:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值