C++基类,派生类,同名覆盖原则

 

 

#运行结果:运行结果

 

##现在来看通过多重继承中,出现同名类成员时的访问机制

 

 

##下面一一分析:

 

int main(array<System::String ^> ^args)
{
 D tmp( 10, 20, 30, 40 );
 tmp.fun_d( ); 
 
 tmp.fun( ); 
 tmp.B::fun( ); 
 tmp.C::fun( );

 system("pause");
    return 0;
}

首先来看tmp.fun_d( );tmp是一个第三继承类对象,它讲调用哪个成员函数呢?首先它会从当前域,及它所属的类区域查找,若查找不到对应的成员函数,它会向前查找。此处tmp所属的类D中已然已经定义了对应的成员函数fun_d( ),所以这里会直接调用 tmp.D::fun_d( );

 

再来看tmp.fun( ).类似上面,它首先从当前域即类D中查找fun()函数,若查找不到,会向前查找,直到找到。基类A中定义了fun(),所以这里会调用属于基类A的成员函数。

 

再来看tmp.B::fun( ).. 很显然,第三继承类D,第二继承类B 中都没有显式定义函数fun( ),这里的调用,意欲何为?由于类B由基类A公有派生而来,所以累B会继承类A 的成员,类似于基类A会在继承类B上映射相应的成员到相应的区域。(通过公有继承, 基类A会把public/protected 成员投射到继承类B相应的public/protected区域上,注意,是一对一投射。)。所以tmp.B::fun( )暗藏着继承机制的原理,及它所调用的实际上是类A的对应成员。

 

当然tmp.C::fun( )这个的访问机制同上。。

 

问题:当类C是通过私有继承机制,来继承类A时,这种访问会是什么样?

 

#运行结果:

运行结果

 

##下面稍微修改下:

 

##注意,此时第三继承类对象tmp调用的成员函数统一都为fun()了;没有特例D::fun_d( )了。下面来区分下调用机制。

 

首先来看tmp.B::fun();

            tmp.C::fun(); //这里和前面的访问机制是一样的,不在赘述。

 

重点来看tmp.fun();不加所属类限定域时。回顾一下,当我们在局部区域定义一个和全局区域同名的变量时,当程序进入局部区域时,是如

 

何区分同名混淆的问题就知道。当程序查找fun()是在那个区域被定义过时,首先从局部区域出发,如果局部区域没有,向前查找,若一直未查找到,编译器会提示出错。这里程序首先就发现了D::fun().查找成功,边不再向前查找了

 

##运行结果:

运行结果

 

##下面来看,动态编译时,系统如何区分基类和派生类中出现同名成员函数的问题,依旧使用上面的例子,略作修改:

##现在来看,在基类A中出现了virtual void fun( )const ; 这就是本片段的重点:虚函数(实现动态编译的基础)。

 

当派生类中出现功能与基类中功能相近的函数调用时,我们就可以把基类中该函数设置成虚函数,在派生类中直接显示调用基类的这个功能

 

函数,然后添加本函数(即派生类)中需要独立实现的功能语句,以此类推,第三派生,第四派生,等等。当然最好使用公有派生,这样可

 

以高效的实现代码重用。

 

##下面切换到具体问题上具体分析:

首先来看主函数:

const int Lim=4;
int main(array<System::String ^> ^args)
{
  A  first( 10 );
  B  second( 20,30 );
  C  third( 30, 40  );
  D  fouth( 60, 70, 80, 90);
  A *po[Lim]={ &first, &second, &third, &fouth };
  for ( int i=0;  i<Lim; i++ )
   po[i]->fun( );

 system("pause");
    return 0;
}

1、首先显式构建了基类,第二派生类(两个),第三派生类(D)的四个对象first,second,third,fouth.并且声明了一个基类指针数组(顾

 

名思义:数组p0[Lim]里面保存的是四个指针,什么指针?指向基类和三个派生类对象地址的指针,根据C++派生类对象可以向上转换成基

 

类对象原则(附注:向下转换是不理智的,因为派生类可能新增加了新的成员,而这些基类是不具备的) ) 。然后显式调用函数fun(),

 

(注意: 在基类中fun()被声明为虚函数,所以在派生类中同名函数前可不比添加virtual关键字,这个系统内部是会区分的)根据虚函数调

 

用原则,例:po[i]->fun() /*当i=2时,这时候po(2)==&third */,系统将根据指针所指向的对象的类型来选择调用哪个函数,而不是根

 

据指针的类型来判断,所以这里将调用C::fun( )。以此类推,当i=0,1,2,3时以此对调用属于类A,B,C,D中的fun()函数。

 

下面是运行结果:

运行结果

##分析下运行结果,首先只看运行结果的前9行:

1、构建A的对象first时将显示Member of class A 这个显而易见。

 

 

2、构建B,C类的各自对象时,都将分别先调用各自基类的构造函数,在这里是A(基类),然后调用本类的构造函数,来初始化本类所新增加的成员,所以结果的2,3,4,5行就很明确了。

 

3、下面是构建类D的对象fouth时,由于类D是从类B,C中抽象出来的,所以生成类D的对象必然会调用类B,,C的构造函数来初始化类D继

 

承而来的成员,所以类B , C 都用的虚拟继承类A,这样类D构建对象时就不会再调用类B  ,C  时两次调用类A了。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值