C++ 继承真正在做的事系列【重载,重写/覆盖,隐藏】

这三个概念是讨论的函数名相同的情况,不要后面要问怎么函数名不同的时候不讨论呢?那你现在最好要确定下函数名不同值得讨论吗?

-----------------------------------------------------------------------------------------------------------------------------------

     
   这个B里面增加什么东西会是上面的概念呢?

-----------------------------------------------------------------

重载:同一个类中定义的函数名相同,参数不同的方法。如果和继承的函数的函数名相同,就要涉及到重写和隐藏。其实不应该拿到这里来讨论的,因为它是指在同一个类中定义的。

----------------------------------------------------------------
重写:这个就涉及到大家常用的virtual关键字了。也就是基类函数用virtual修饰,子类中定义一个函数与其同名,而且参数相同。这里就是所谓的多态。如果您还不知道多态,请百度下。 当基类中的某个函数virtual后,子类创建基类对象,并用子类的重写的方法放入基类本来分好的代码段中,把以前的代码覆盖掉,也就是把函数重写了。其实这就是所谓的动态绑定技术。这样的话无论你是用基类指针还是派生类指针访问该函数,执行的都是子类中重新写的代码。

----------------------------------------------------------------
隐藏: 什么是隐藏?看代码

例1


class A

public: 
void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public: 
    
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); 
return 0;
}

结果:A:fun1
      A:fun1

 

这是正常情况下,B继承了A的fun1,所以用两种类型的指针调用的都是同一个fun1。下面在B中分3种情况加一个同名函数。

 

例2


class A

public: 
void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public: 
        void fun1()
{
   cout<<"B:fun1"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); 
return 0;
}
结果:A:fun1
      B:fun1
子类同名函数,参数相同,但基类函数没有virtual,这个时候是隐藏。用子类的指针只能访问子类的那个fun1,不能访问继承自基类的fun1,其实它仍然存在与基类的代码段中,
因为用A类型指针能头访问它。这也是隐藏名字的由来,基类的fun1对子类指针隐藏了,躲猫猫了,但仍然存在,要通过基类指针访问。

 

例3


class A

public: 
void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public: 
        void fun1(int i)
{
   cout<<"B:fun1"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); //这里编译报错
return 0;
}
结果:error C2660: “B::fun1” : 函数不接受 0 个参数
基类同名函数非virtual,子类参数不同。那么当用子类指针进行访问继承自A的fun1时,会访问不了,报错。当你注释掉以后,用A的指针还是能访问的。

 

例4


class A

public: 
virtual void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public:

void fun1(int i)
{
   cout<<"B:fun1 int"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); 
return 0;
}
结果:和上一种情况一样。
基类同名函数是virtual的,子类定义了一个同名参数不同的,但还是隐藏的。


结论:子类和基类定义同名函数的总共4种情况(virtual两种,参数两种,总共2*2)都讨论过了。综上所述,当基类的某函数声明为virtual,使用动态绑定技术,当最终创建子类对象的时候,如果子类种有同名且参数相同即完全一样的函数的时候,这个时候基类的virtual函数代码才最终确定。也实现了函数的重写。当创建子类对象的时候,如果没碰到同名参数相同的函数,会使用基类定义的代码。这个时候如果子类也定义了一个同名的函数,那么会隐藏掉基类的同名函数。这就是4种情况的另外3种情况。

补充:

class A
{
public:
virtual void show()
{
   cout<<"ok in a"<<endl;
}
};
class B :public A
{

void show()
{
   cout<<"ok in b"<<endl;
}
};

int main()
{
B *bp=new B;
A *ap=(A*)bp;
ap->show();
//bp->show(); //出现编译错误 error C2248: “B::show” : 无法访问 private 成员(在“B”类中声明)
}

出现编译错误,是因为B中的show()是private的。bp调用时权限是B定义的,ap调用权限是A定义的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值