|  | 
				
					
	
		
		
		◆ 读程序:
  1 #include<iostream> 2
  using namespace std; 3
  class B1 4
   { 5
  public: 6
  void Setb1(int i) 7
   { 8
  b1=i; 9
  } 10
  void Printb1() 11
   { 12
  cout<<"b1="<<b1<<endl; 13
  } 14
  private: 15
  int b1; 16
  }; 17
  class B2 18
   { 19
  public: 20
  void Setb2(int i) 21
   { 22
  b2=i; 23
  } 24
  void Printb2() 25
   { 26
  cout<<"b2="<<b2<<endl; 27
  } 28
  private: 29
  int b2; 30
  }; 31
  class D:public B1,B2 32
   { 33
  public: 34
  void Setd(int i,int j) 35
   { 36
  d=i; 37
  Setb2(j); 38
  } 39
  void Printd() 40
   { 41
  Printb2(); 42
  cout<<"d="<<d<<endl; 43
  } 44
  private: 45
  int d; 46
  }; 47
  int main() 48
   { 49
  D objd; 50
  objd.Setb1(16); 51
  objd.Printb1(); 52
  objd.Setd(24,76); 53
  objd.Printd(); 54
  return 0; 55
  } 56
  
显示结果为: b1=16 b2=76 d=24
 分析:多重继承派生类D有2个基类,一个是公有继承B1类,另一个是私有继承B2类。使用class定义派生类时,默认的继承方式为私有,使用struct定义派生类时,默认的继承方式为公有。由于B2类被私有继承,它的公有成员函数Setb2()在派生类D中为私有成员,可被该类的成员函数访问,但不能被该类的对象所访问。
 
例如:
  1 #include<iostream> 2
  using namespace std; 3
  class B1 4
   { 5
  public: 6
  B1(int i) 7
   { 8
  b1=i; 9
  } 10
  int Getd() 11
   { 12
  return b1; 13
  } 14
  protected: 15
  int b1; 16
  }; 17
  class B2 18
   { 19
  public: 20
  B2(char i) 21
   { 22
  b2=i; 23
  } 24
  char Getd() 25
   { 26
  return b2; 27
  } 28
  protected: 29
  char b2; 30
  }; 31
  class D:public B1,public B2 32
   { 33
  public: 34
  D(int ,char ,double); 35
  double Getd() 36
   { 37
  return d; 38
  } 39
  private: 40
  double d; 41
  }; 42
  D::D(int i,char j,double k):B1(i),B2(j),d(k) 43
   { 44
  } 45
  int main() 46
   { 47
  B1 b1(18); 48
  B2 b2('G'); 49
  D d(15,'H',6.56); 50
  cout<<"b1="<<b1.Getd()<<"\nb2="<<b2.Getd()<<endl; 51
  cout<<"\nD::b1="<<d.B1::Getd()<<"\nD:b2="<<d.B2::Getd() 52
  <<"\nD::d="<<d.Getd()<<endl; 53
  B1 *ptrb1=&d; 54
  B2 rb2=d; 55
  cout<<"\nb1="<<ptrb1->Getd()<<"\nb2="<<rb2.Getd()<<endl; 56
  return 0; 57
  } 58
  
结果显示: b1=18 b2='G' D::b1=15 D::b2='H' D::d=6.56 b1=15 b2='H' 分析:
 该程序中值得注意的是3个类中都有一个同名函数Getd(),在使用D类对象d引用该函数d.Getd()时,应该选用D类定义的Getd()函数。如果引用B1类或B2类中定义的Getd()函数时,必须使用类名加作用域运算符加以限定。另外,该程序也出现赋值兼容规则的使用,由于D类是B1类和B2类的子类型,下述两条语句是符合赋值兼容规则的:
 B1  *ptrb1=&d;
 B2  &rb2=d;
 
 ◆虚基类
 读程序:
 
  #include<iostream> 
  using namespace std; 
  class A 
   { 
  public: 
  A(int i) 
   { 
  a=i; 
  cout<<"Constructor called.A \n"; 
  } 
  void Print() 
   { 
  cout<<a<<","; 
  } 
  ~A() 
   { 
  cout<<"Destructor called.A \n"; 
  } 
  private: 
  int a; 
  }; 
  class B1:public A 
   { 
  public: 
  B1(int i,int j):A(i) 
   { 
  b1=j; 
  cout<<"Constructor called.B1 \n"; 
  } 
  void Print() 
   { 
  A::Print(); 
  cout<<b1<<","; 
  } 
  ~B1() 
   { 
  cout<<"Destructor called.B1 \n"; 
  } 
  private: 
  int b1; 
  }; 
  class B2:public A 
   { 
  public: 
  B2(int i,int j):A(i) 
   { 
  b2=j; 
  cout<<"Constructor called.B2 \n"; 
  } 
  void Print() 
   { 
  cout<<b2<<","; 
  } 
  ~B2() 
   { 
  cout<<"Destructor called.B2 \n"; 
  } 
  private: 
  int b2; 
  }; 
  class C:public B1,public B2 
   { 
  public: 
  C(int i,int j,int k,int l,int m):B1(i,j),B2(k,l) 
   { 
  c=m; 
  cout<<"Constructor called.C \n"; 
  } 
  void Print() 
   { 
  B1::Print(); 
  B2::Print(); 
  cout<<c<<endl; 
  } 
  ~C() 
   { 
  cout<<"Destructor called.C \n"; 
  } 
  private: 
  int c; 
  }; 
  int main() 
   { 
  C c(16,19,23,25,38); 
  c.Print(); 
  return 0; 
  }运行结果:Constructor called.A
 Constructor called.B1
 Constructor called.A
 Constructor called.B2
 Constructor called.C
 16,19,25,38
 Destructor called.C
 Destructor called.B2
 Destructor called.A
 Destructor called.B1
 Destructor called.A
 
 虚基类的说明格式如下:
 virtual <继承方式><基类名>
 C++规定:在派生类构造函数的成员初始化表中出现的虚基类构造函数优先于非虚基类构造函数的调用。又规定:只在创建对象的派生类构造函数中调用虚基类构造函数,而派生类的基类构造函数中不再调用虚基类构造函数,这就保证了对虚基类成员只初始化一次。
 分析下列程序的输出结果,并与上例的输出结果比较有何不同:
 
  #include<iostream> 
  using namespace std; 
  class A 
   { 
  public: 
  A(int i) 
   { 
  a=i; 
  cout<<"Constructor called.A \n"; 
  } 
  void Print() 
   { 
  cout<<a<<","; 
  } 
  ~A() 
   { 
  cout<<"Destructor called.A\n"; 
  } 
  private: 
  int a; 
  }; 
  class B1:virtual public A 
   { 
  public: 
  B1(int i,int j):A(i) 
   { 
  b1=j; 
  cout<<"Constructor called.B1 \n"; 
  } 
  void Print() 
   { 
  A::Print(); 
  cout<<b1<<","; 
  } 
  ~B1() 
   { 
  cout<<"Destructor called.B1 \n"; 
  } 
  private: 
  int b1; 
  }; 
  class B2:virtual public A 
   { 
  public: 
  B2(int i,int j):A(i) 
   { 
  b2=j; 
  cout<<"Constructor called.B2 \n"; 
  } 
  void Print() 
   { 
  A::Print(); 
  cout<<b2<<","; 
  } 
  ~B2() 
   { 
  cout<<"Destructor called.B2 \n"; 
  } 
  private: 
  int b2; 
  }; 
  class C:public B1,public B2 
   { 
  public: 
  C(int i,int j,int k,int l,int m):B1(i,j),B2(k,l),A(i) 
   { 
  c=m; 
  cout<<"Constructor called.C \n"; 
  } 
  void Print() 
   { 
  B1::Print(); 
  B2::Print(); 
  cout<<c<<endl; 
  } 
  ~C() 
   { 
  cout<<"Destructor called.C \n"; 
  } 
  private: 
  int c; 
  }; 
  int main() 
   { 
  C c(16,19,23,25,38); 
  c.Print(); 
  return 0; 
  } 
 运行结果: Constructor called.A  Constructor called.B1 Constructor called.B2 Constructor called.C 16,19,23,25,38 Destructor called.C Destructor called.B2 Destructor called.B1 Destructor called.A 分析:
 将该程序与上例程序比较仅有如下不同:1、在类B1类和B2类公有继承共同基类时加了关键字virsual,即类A被说明为虚基类;
 2、在派生类C的构造函数的成员初始化表中增添了A(i)项,即调用虚基类A的构造函数。
 输出结果比较:1、虚基类A的构造函数只调用一次,并且是最先调用,同时虚基类A的西沟函数也只调用一次;
 2、输出两次类A的数据成员a的值都是16。
   
	    
    
 |