类的继承是在现有类的基础上创建新类,并拓展现有类的功能的机制,称现有的类为基类,新建立的类为派生类。
继承导致同名覆盖:派生类相同名称的数据成员或成员函数会覆盖掉基类的同名成员。
派生类特点:
1.派生类继承了基类的所有成员,派生类对象包括基类的数据成员,也可以直接调用基类的公有函数。
2.派生类对象不可以直接访问基类的私有成员。
3.派生类对象可以通过基类的公有函数访问基类的私有成员
4.派生类可以访问基类的protected成员
定义派生类:
class 派生类名:继承方式 基类1,继承方式 基类2,继承方式 基类3…
继承方式有:public,protected,private
class Hugeint: public Hegeint1
{
public:
protected:
private:
}
派生类不继承基类的构造函数,析构函数和默认赋值运算符。
使用protected属性:不想被用户代码访问,但希望被派生类访问
- public继承:基类的public,protected成员在派生类保持原属性
- protected继承:基类的public,protected成员在派生类变为protected属性
- private继承:基类的public,protected成员在派生类变为private属性
同名覆盖:派生类修改基类的成员,在派生类中声明了一个与基类同名的新成员,则在派生类中只能访问该成员而无法访问与该成员同名的基类成员。
定义派生类类
class son:public father1,public father2,.....,public fathern
{
}
1.派生类构造函数
派生类名::派生类名(基类所需形参,本类成员所需形参):基类1(基类参数表),基类2 基类参数表…
{
}
调用顺序:先基类,再派生类(father1,father2,…,fathern,son)
注:调用顺序由类定义时的顺序决定,与构造函数形式无关
Son::Son(int x1,int x2,int x3,int x4):father3(x1),father1(x2),father2(x3)
{
}
2.派生类析构函数
派生类析构函数只负责清理它新定义的堆成员(指针变量),无法继承
调用顺序:先派生类再基类(son,fathern,…,father2,father1)
后面会讲到用虚函数定义来定义析构函数保证内存不发生泄露
注:调用顺序由类定义时的顺序决定,与构造函数形式无关
虚基类
多继承与二义性:
多继承:派生类有多个直接基类或间接基类
二义性:派生类的众多基类中有两个基类具有相同的成员,即系统无法选取,会报出ambiguous错误,即出现了二义性
虚基类
为解决二义性,可将出现二义性的共同基类设置为虚基类,这样创建派生类对象时,虚基类的构造函数只会调用一次,即只有一份拷贝不会再引起二义性问题。
待续(自己没搞清楚清楚对不起了orz)
转换与继承
class A1
{
public:
A1(int x,int y);
int value,data;
};
class A2:public A1
{
public:
A2(int x,int y,int z);
int score;
};
A1::A1(int x,int y)
{
value=x;
data=y;
}
A2::A2(int x,int y,int z):A1(x,y)
{
data=A1::data;
value=A1::value;
score=z;
}
1.派生类对象转换为基类对象
int main(int argc, char** argv)
{
A3 a(1,2,3,4);
A1 b(2,3);
b=a;
}
派生类a赋值给基类b,此时派生类被截成了两部份,一部分为从基类继承来的数据成员赋值给了b,另一部分为派生类特有的数据成员,称为对象截断。
2.基类对象指针指向派生类对象
int main(int argc, char** argv)
{
A3 a(1,2,3,4);
A1 *b=dynamic_cast<A1*>(&a);
cout<<b->plus();
}
注意:*b即为被截断的派生类对象a的公有部分,此时b->plus调用的为基类函数plus(后面会介绍如何使用基类指针调用派生类同名函数 )
3.基类到派生类不存在转换
C++编译器可以自动将派生类对象转换为基类对象(隐式类型转换)
未完待续~