继承

继承:在已有类的基础上创建新类的过程。
一个B类继承A类,或称从类A派生类B,类A称为基类(父类),类B称为派生类(子类)。
类继承关系的语法形式
class
派生类名:基类名表
数据成员和成员函数声明
};
基类名表构成:
访问控制 基类名1,访问控制 基类名2 ,…,访问控制 基类名n
访问控制表示派生类对基类的继承方式,使用关键字:
public:(公有继承)基类成员在派生类中的访问权限保持不变,也就是说,基类中的成员访问权限,在派生类中仍然保持原来的访问权限。
private :(私有继承)基类所有成员在派生类中的访问权限都会变为私有(private)权限。
protected:(保护继承)基类的共有成员和保护成员在派生类中的访问权限都会变为保护(protected)权限,私有成员在派生类中的访问权限仍然是私有(private)权限。
派生类的生成过程经历了三个步骤:

  • 吸收基类成员(全部吸收(构造、析构除外),但不一定可见):在C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。
  • 改造基类成员:通过在派生类中定义同名成员( 包括成员函数和数据成员)来**屏蔽(隐藏)**在派生类中不起作用的部分基类成员。
  • 添加派生类新成员:仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。
    子类对象空间总是不小于基类对象
    基类对象:a b
    子类对象:a b c (a和b为基类对象,c为子类对象)
#include <iostream>
using namespace std;
class A{
public:	
	int a;	
	int b;
private:	
	int c;
protected:
	int d;
};
class B: public A
{
private:
	int c;
};
int main(){
cout <<”size of A is" << sizeof(A);//16
cout<<" size ofB is" << sizeof(B); //20
}
/*
基类(A)对象:a b c d
子类(B)对象:a b c d c
*/

重名成员
派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽了基类的同名成员。
在派生类中使用基类的同名成员,显式地使用类名限定符:
类名::成员

class base{
 public:
   int a;
   int b;
};
class derived:public base{
public :
   int b;   
   int c;
};
void f(){
 derived d;
 d.a=1;
 d.base::b=2;
 d.b=3;
 d.c=4;
};
/*
base:a b
derived:a b b c
*/

派生类中访问静态成员:
基类定义的静态成员,将被所有派生类共享(基类和派生类共享基类中的静态成员)。
派生类中访问静态成员,用以下形式显式说明:
类名::成员或通过对象访问对象名 .成员
基类的初始化
派生类构造函数(变元表) :基类(元表),对象成员1(变元表)…对象成员n (变元表);
构造函数执行顺序:基类→对象成员→派生类
派生类构造函数和析构函数的使用原则:
1.基类的构造函数和析构函数不能被继承
2.如果基类没有定义构造函数有无参的构造函数,派生类也可以用定义构造函数
3.如果基类无无参的构造函数,派生类必须定义构造函数
4.如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造
5.派生类是否定义析构函数与所属的基类无关
派生类构造函数的一般格式为:
派生类::派生类名(参数总表):基类名(参数表)
{
//派生类新增成员的初始化语句
}
派生类析构函数
1.当派生类中不含对象成员时:
创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数
撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数
2.当派生类中含有对象成员时:
定义派生类对象时,构造函数的执行顺序**:基类的构造函数→对象成员的构造函数→派生类的构造函数**;
撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数

class B{
public:
B(){
 cout<<"B()"<<endl; 
 }
~B(){
 cout<<"~B()"<<endI; 
 }
};
class D:public B{
public:
D(){ 
cout<<"D()"<<endl; 
}
~D(){
 cout<<"~D()"<<endl;
  }
};
int main()
{
D d;
return 0;
}
/*
B()
D()
~D()
~B()
*/

多继承
一个类有多个直接基类的继承关系称为多继承
多继承声明语法:
class派生类名 :访问控制 基类名1,访问控制 基类名2 ,… ,访问控制 基类名n
{
数据成员和成员函数声明
};
多继承的构造函数
派生类名(参数总表):基类名1(参数表1),基类名2(参数表.),…,基类名n(参数
表n)
{
//派生类新增成员的初始化语句
}
多继承方式下构造函数的执行顺序:
1.先执行所有基类的构造函数
2.再执行对象成员的构造函数
3.最后执行派生类的构造函数
析构函数的执行顺序:(与多继承方式下构造函数的执行顺序完全相反)
1.首先对派生类新增的数据成员进行清理
2.再对派生类对象成员进行清理
3.最后才对基类继承来的成员进行清理
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类
虚继承声明使用关键字:virtual

class B{
public:
int b;
};
class B1:virtual public B{
 private:
  int b1 ;
  };
class B2:virtual public B{
 private:
  int b2;
  };
class C:public B1,public B2{
 private:
  float d;
  };
/*
C cc;
cc.b;
cc.B1::b和cc.B2:b引用是同一个基类B的子对象,使用虚继承之后,可以直接用cc.b表示

赋值兼容规则指在程序中需要使用基类对象的任何地方,都可以用公有派生类的对象来替代。
赋值兼容规则中所指的替代包括以下的情况:
1.派生类的对象可以赋给基类对象
2.派生类的对象可以初始化基类的引用
3.派生类的对象的地址可以赋给基类类型的指针
根据复制兼容规则,以下几种情况是合法的:
(1)可以用派生类对象给基类对象赋值。例如:
Base b;
Derived d;
b=d;
对象b中所有数据成员都将具有对象d中对应数据成员的值。
(2)可以用派生类对象来初始化基类的引用。例如:
Derived d;
Base &br=d;
(3)可以把派生类对象的地址赋值给指向基类的指针。例如:
Derived d;
Base *bptr=&d;
(4)可以把指向派生类对象的指针赋值给指向基类对象的指针。例如:
Derived *dptr,obj; dptr=&obj;
Base *bptr=dptr;
注意:在替代之后派生类对象可以作为基类对象来使用,但只能使用从基类继承的成员。
赋值兼容应注意的问题
(1)声明为指向基类的指针可以指向它的公有派生类的对象,但不允许指向
它的私有派生类的对象。例如:
class B {…};
class D: private B{ …};
B b1,*pbl;
D d1;
pb1=&b1;//合法,基类B的对象b1和B类的指针
pb1=&d1;//非法,不允许将基类指针指向它的私有派生类对象
(2)允许将一个声明为指向基类的指针指向其公有派生类对象,但是不能将
一个声明为指向派生类对象的指针指向其基类的一.个对象。
(3)声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来直接访问派生类中从基类继承来的成员,而不能直接访问公有派生类的定义的成员。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值