继承性

今天呢我们来看一下C++中的继承^-^.

继承性是一个非常自然的概念,现实中很多事物是具有继承特性的。人们一般用层次分类的方法来描述它们的关系。


在这个分类树中建立了一个层次结构,最高层次的最普遍、最一般的。每一层都比它的前一层更具体,低层含有高层的特性,同时也与高层有细微的不同,它们之间是基类和派生类的关系。

类的继承是一种复用手段,新的类从已有类那里得到已有的特性并在其基础上增加新的特性,在继承关系里基类继承派生类的成员,由此达到复用的目的。继承有三种类型,分别是:公有继承、私有继承和保护继承。它们的关系如图所示:

 

我们来看一个例子:

class people//父类

{

public:

       people(const string&name)

              :_name(name)

       {}

       void show()

       {

              cout <<_name << endl;

       }

private:

       string _name;

};

class student :public people//子类

{

public:

       void _show()

       {

              cout <<_name << endl;

              cout <<_num << endl;

       }

protected:

       char _num;

};

例子中我们可以发现类不可以直接调用父类的_name,因为_name是父类的私有成员,不可在类外直接访问,所以我们引出了保护成员的概念,保护成员在被子类继承后直接访问,但不可以在父类和子类之外的地方被使用。如果我们想要访问父类中的私有成员,只能通过调用公有成员函数来调用。

继承可以分为单继承和多继承:


多继承也分为public、protected、private,只不过比单继承更复杂一些。

我们再来看一些我刚学到的术语:

隐藏/重定义 :子类与父类的同名成员,子类隐藏父类的成员,在访问时按照就近原则,想要指定访问,必须指定作用域。
    重载:(前提:在同一个作用域)函数名相同,参数不同或者返回值可以不同。
    重写/覆盖:在子类定义一个与父类完全相同的虚函数,要求返回值、函数名、参数列表都相同。

构造时先构造父类后构造子类,析构时要先析构子类后析构父类。

总结:

1.    基类的私有成员在派生类中是不能直接被访问的,如果想要直接访问可定义为保护成员。公有继承时,一个子类就是一个父类,子类继承父类的东西在子类里面访问权限不变,子类可以赋给父类对象/指针/引用,会发生切片/切割。保护继承和私有继承时,一个子类里面有一个父类,子类继承父类的东西在子类里面访问权限发生改变,子类就无法赋值给父类。

2.    使用关键字class时默认的继承方式是private,而使用struct时默认继承方式是public,使用时显示写出来较好。

3.    在实际运用中,一般都使用public继承,极少情况下才会用到protected和private继承。

赋值兼容规则:

先看一下下面的代码:

class people

{

public:

       void show()

       {

              cout << _name << endl;

       }

protected:

       string _name;

};

class student:public people

{

public:

       void show()

       {

              cout << _num << endl;

       }

protected:

       char _num;

};

void main()

{

       people p;

       student s;

       p = s;//子类对象可以赋值给父类对象

       s = p;//父类对象不可以赋给子类对象

       people* pa = &s;

       people& pa = s;//子类指针/引用可以指向父类对象

       student* sa = &p;

       student& sb = p;//父类指针/引用不可以指向子类对象(可以通过强制转换指向)

       student* sa = (student*)&p;

       student& sb = (student&)p;

}
继承体系中的作用域:
1.在继承体系中基类和派生类都有独立的作用域。
2.子类和父类中有同名成员、子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用基类:基类成员访问)-隐藏-重定义
3.注意在实际中在继承体系里面最好不要定义同名的成员。   
派生类中的默认成员函数:
    在继承关系里,如果派生类没有显示的定义6个默认成员函数(构造函数,拷贝构造,析构函数,赋值运算符重载,取地址操作符重载,const修饰的取地址操作符重载),编译系统则会默认的的合成这6个成员函数。

(1)   当基类构造函数不带参数时, 派生类不一定需要定义构造函数, 系统会自动的调用基类的无参构造函数; 然而当基类的构造函数那怕只带有一个参数, 它所有的派生类都必须定义构造函数,因为参数传递给要调用的基类构造函数。

(2)   如果派生类的基类也是一个派生类, 每个派生类只需负责其直接基类数据成员的初始化,依次上溯。

还有,有多继承和菱形继承时会出现二义性,下面来看一段代码:

 

class A

{

public:

       int a;

};

class B :virtualpublic A

{

public:

       int b;

};

class C :virtualpublic A

{

public:

       int c;

};

class D :public B,public C

{

public:

       int d;

};

void main()

{

       D dd;

       dd.B::a = 1;

       dd.b = 5;

       dd.C::a = 3;

       dd.c = 6;

       dd.d = 7;

       cout << sizeof(dd) << endl;

       B bb;

       cout << sizeof(bb) << endl;

}

 

为什么我们的结果会是这样?我们来看一下内存分布:

 



从图中可以发现,使用虚继承后解决了二义性的问题,多了虚基表的空间所以sizeof(dd)变成了24。

虚继承有些复杂,在实际应用中我们一般不会用这么复杂的继承体系。

**友元关系不能继承,基类的友元不能访问派生类的私有成员和保护成员。

**基类定义了static成员,则整个继承体系里面只有那么一个成员,无论派生多少类,只有这一个静态成员。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值