[其中一些文字转自某文章,现在找不到出处 - - ]
C++继承可以提高代码的复用性,减少编码过程的劳动量。但是不能滥用继承关系。
一、使用继承关系主要遵循以下两个要点:
1.如果A类与B类是没有关系的,不能 用“为了使B类功能更多” 这个理由强用继承关系。
该干嘛干嘛。
2.如果B类使用到了A类的功能,还要分两种情况进行讨论。
- 在逻辑上,B是A的“一种”(a kind of),则允许B继承A的功能。比如男人与人。
- B是A逻辑上的一部分,则不允许继承。他们应该是组合关系,而不是派生关系。例如眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头(Head)的一部分,所以类Head 应该由类Eye、Nose、Mouth、Ear 组合而成,不是派生而成。如果允许Head 从Eye、Nose、Mouth、Ear 派生而成,那么Head 将自动具有Look、Smell、Eat、Listen 这些功能。
(add:派生类不会继承基类的构造函数和析构函数。派生类可以对基类的同名函数进行覆盖或者重载。不同的继承方式可以获得对基类成员不同的访问属性
派生类和基类成员的交互有两种,一是新增的成员变量对基类成员变量的访问,二是派生类对象对基类成员的访问。
二、各种继承方式的区别
当派生类继承方式为public时,(一)和(二)对基类公有成员和保护成员的访问属性不变(都能访问),私有成员不能访问。
当派生类继承方式为protect时,基类中public和protect属性的变量对于派生类来说相当于public的访问属性。对于派生类对象(外部)来说相当于protect属性。
注意:一个类的private和protect属性变量都不能被外部访问,但protect属性可由派生类(不是派生类对象)访问
当派生类的继承方式为private时,基类中所有属性的变量都变成派生类的私有变量。派生类的新增变量可以访问,而派生类对象不能访问。且当派生类再作为新的基类被其他类继承时,最原始那个基类的东西什么也不会被继承到 。如果想要在派生类中也调用基类一样的公共接口,可以利用同名覆盖原则,在派生类中声明与基类一样的接口,在派生类接口的实现中调用基类的接口函数。
三、派生类的构造函数和析构函数
派生类的构造函数初始化参数列表:
1.因为基类的构造函数不能被派生类继承,所以需要在派生类构造函数的参数列表中将参数传给基类构造函数(在需要参数的情况下o(≧口≦)o)
2.当该类有包含其他的类,而其他类的初始化又需要参数。这时需要将参数从派生类的构造函数初始化参数列表传到成员类的构造函数里。
PS:不管对于哪种继承方式,基类的private成员都是不能被派生类访问,也不能被类对象访问。
格式大概像这样
派生类名::派生类名(参数表):基类名1(参数表1),...基类名m(参数名m),
内嵌对象名(内嵌对象参数表1),...,内嵌对象名n(内嵌对象参数表n)
{
初始化派生类新成员的语句;
}
基类构造函数与内嵌对象的构造函数顺序可以自己安排 = =
至于执行顺序
1.首先执行基类的构造函数,若有多个基类,就找他们在派生类声明时的顺序依次执行构造函数 2.其次执行内嵌对象的构造函数,若有多个,顺序就按他们的声明顺序执行 3.最后是派生类构造函数的代码哦
派生类的析构函数
由于基类的析构函数也不能被子类继承,所以子类要有析构函数释放那些(新增的)资源。
当执行子类析构函数的时候,系统会默认去调用基类的析构函数和内嵌类的析构函数。所以,不用紧张 - -
析构函数的调用顺序刚好与构造函数的调用顺序相反,也就是
1.首先派生类的析构函数,清理新增加的成员 2.其次执行内嵌类的析构函数,如果有多个内嵌类,执行顺序就与他们的构造函数顺序相反(与内嵌类的声明顺序相反) 3.最后执行基类的析构函数,如果有多个基类,执行顺序与他们的构造函数顺序相反(与在派生类的声明顺序相反)
派生类与基类成员的作用域
在派生类中变量或函数名与基类中的变量或函数名相同时,就会把基类的给覆盖。这时我们要访问基类中的同名变量,要使用类的作用域标识符。
大概像这样
类::变量/函数
虚基类及其派生类的构造函数
假如现在有4个类,第一个是祖宗类,第二第三个是父类母类,第四个是子类。父母类继承自祖宗类,子类继承父母类(多继承)。
这时当父母类继承祖宗类的时候,使用虚基类继承(virtual)的话,不管在父类还是在母类访问祖宗类,都是访问内存中的同一块地址上的东西。而子类继承父母类,访问祖宗类时,也是和父母访问的是同一块的东西。
规格大概是这样子
class chile : virtual public base_class//虚拟共有继承哦 =。= { };
这时派生类的构造函数构造函数(假如祖宗类的构造函数带有参数,不然就没什么事了~):
child(int y) : base_class(int y) { }
只需要把参数传给基类就可以了,不必理会中间那些类(反正在内存里只有一份..
兼容赋值规则
继承里有个特性,叫兼容赋值。说子类的值可以赋给基类哦 = =。
具体来说,有下面三种情况
1.派生类的对象可以赋值给基类对象
2.基类指针可以指向派生类对象
3.派生类对象可以初始化基类引用
大概像这样子
1.基类对象 = 派生类对象; 2.base* pointer = &child; 3.base& reference = child;
需要注意的是,不管是基类的指针或是引用都好,在指向派生类时,只能使用基类那部分数据。派生类新增的内容是不能使用基类指针/引用访问的。
这项技术可以这样用,假如这里有个类族(也就是所有类都有共同的基类)。对于类族中的每一个派生类,我们可以使用一种统一的手段就访问到他们所继承的属于基类的那部分内容,也就是使用基类引用/指针反问他们。
大概可以这样弄
void visit(base* pointer)//这是一个访问函数,传入参数是指向基类的指针(也可以是引用 { //由于赋值兼容原则,所以可以将子类也赋值给他,从而访问 //···· }