派生类成员对基类的访问

时间:2022-10-02 19:58:59

作用域分辨符:
就是::用来限定要访问的成员所在的类的名称;
表达式是:
基类名::成员名;            //数据成员
基类名::成员名(参数表)//成员函数
加入作用域分辨符可以防止同名覆盖,也可以保证访问不出现二义性;(避免二义性,内存中只有一份拷贝,用到虚基类)
例子:
class B1
{
public:
 int nV;
 void fun()
 {
  cout<<"member of B1"<<endl;
 }
};

class B2
{
public:
 int nV;
 void fun()
 {
  cout<<"Member of B2"<<endl;
 }
};

class C1:public B1,public B2
{
public:
 int nV;
 void fun()
 {
  cout<<"member of C1"<<endl;
 }
};

void main()
{
 C1 c1;
 c1.nV = 1;
 c1.fun();
 c1.B1::nV = 10;
 cout<<c1.B1::nV<<endl;
 c1.B1::fun();
 c1.B2::fun(); 
}
下面的语句就是作用域访问,说明访问的是类B1和类B2的函数fun()
c1.B1::fun();
c1.B2::fun();
如果没有这样的作用域名,直接调用fun(),就会访问派生类中的fun(),造成同名覆盖;
注意:如果派生类中没有声明同名的函数fun(),则直接通过c1.fun()的方式调用函数会出错,不知道是谁的fun(),(有可能是B1的或者是B2的)这就是二义性;


虚基类:
class B1
{
public:
 int nV;
 void fun()
 {
  cout<<"member of B1"<<endl;
 }
};

class B2
{
public:
 int nV;
 void fun()
 {
  cout<<"Member of B2"<<endl;
 }
};

class C1:virtual public B1//, virtual public B2
{
public:
 int nV;
//  void fun()
//  {
//   cout<<"member of C1"<<endl;
//  }
};

void main()
{
  C1 c1;
 c1.nV = 1;
 c1.fun();
 c1.B1::nV = 10;
 cout<<c1.B1::nV<<endl;
 c1.B1::fun();
/* c1.B2::fun();*/ 
}
把上面的代码改动一下,就是下面的结果:

member of B1
10
member of B1
Press any key to continue
这时候调用基类B1的时候采用虚基类的继承方法,这时候从不同路径继承过来的同名函数成员在内存中就只有一个拷贝,同一个函数名也只有一个映射,这样也就解决了同名函数的
唯一标示问题。
此时派生类中就不用在定义同名函数了,否则又要同名覆盖;
虚基类中也可以穿插作用域分类法;作用域访问仍起作用;
上面的例子是一个派生类继承一个基类,虚基类一般都是一继承一或者多继承一,不能一继承多,不然可能会造成多义性,特别是两个基类中有同名函数的时候;
两个基类函数没有同名函数的时候,通过虚基类继承过来派生类可以实现一继承多;
例子:
class B1
{
public:
 int nV;
 void fun()
 {
  cout<<"member of B1"<<endl;
 }
};

class B2
{
public:
 int nV;
 void fun2()
 {
  cout<<"Member of B2"<<endl;
 }
};

class C1:virtual public B1, virtual public B2
{
public:
 int nV;
 void fun1()
 {
  cout<<"member of C1"<<endl;
 }
};

void main()
{
  C1 c1;
 c1.nV = 1;
 c1.fun1();
 c1.B1::nV = 10;
 cout<<c1.B1::nV<<endl;
 c1.fun();
 c1.fun2(); 
}

结果是:
member of C1    //调用自己的函数成员
10
member of B1    //调用B1类的成员函数(虚基类的方式继承)
Member of B2    //调用B2类的成员函数(虚基类的方式继承)
Press any key to continue