一.继承的定义
当一个派生类继承一个基类时,需要在派生类的类派生列表中明确的指出它是从哪个基类继承而来的。类派生列表的形式如下:
class 派生类
: public/private/protected 基类
{
};
派生类生成的三个步骤:
- 吸收基类成员
- 修改基类成员
- 增加自己新成员
二.继承的局限
不管什么继承方式,下面这些基类特征是不能从基类继承下来的:
- 构造函数
- 析构函数
- 用户重载的operator new/delete运算符
- 用户重载的operator=运算符
- 友元关系
三.派生(继承)方式对基类成员的访问权限
继承方式有3种,分别是
- public公有继承
- protected保护性继承
- private私有继承
继承方式 | 基类成员访问权限 | 在派生类中访问权限 | 派生类(子类)对象访问 |
公有继承 | public protected private | public protected private | 可直接访问 不可直接访问 不可直接访问 |
保护继承 | public protected private | protected protected 不可直接访问 | 不可直接访问 |
私有继承 | public protected private | private private 不可直接访问 | 不可直接访问 |
其中在不声明继承方式时默认时private。私有继承只能被继承一代,因为在私有继承结束后所有的成员都变为私有了,也就不能在被继承了。
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class Point
{
private:
int _ix;
public:
int _iy;
Point(int ix=0,int iy=0)
:_ix(ix)
,_iy(iy)
{
cout<<"Point(int ix=0,int iy=0)"<<endl;
}
~Point()
{
cout<<"~Point()"<<endl;
}
int getX() const
{
return _ix;
}
};
class Point3D
:private Point
{
private:
int _iz;
public:
Point3D(int ix=0,int iy=0,int iz=0)
:Point(ix,iy)
,_iz(iz)
{
cout<<"Point3D(int ix=0,int iy=0,int iz=0)"<<endl;
}
~Point3D()
{
cout<<"~Point3D()"<<endl;
}
int getZ()const
{
return _iz;
}
void print() const
{
cout<<"ix ="<<getX()<<"iy ="<<_iy<<"iz ="<<_iz<<endl;
}
};
class Point4D
:public Point3D
{
private:
int _id;
public:
Point4D(int x=0,int y=0,int z=0,int d=0)
:Point3D(x,y,z)
,_id(d)
{
cout<<"Point4D(int x=0,int y=0,int z=0,int d=0)"<<endl;
}
~Point4D()
{
cout<<"~Point4D()"<<endl;
}
void print()const
{
cout<<"_ix = "<<getX()<<endl<<"_iy = "<<_iy<<endl //error
<<"_iz = "<<getZ()<<endl<<"_id = "<<_id<<endl;
}
};
int main()
{
Point4D P(1,2,3,4);
P.print();
return 0;
}
应该将Point3D类继承Point的方式变为public/protected。
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class Point
{
private:
int _ix;
public:
int _iy;
Point(int ix=0,int iy=0)
:_ix(ix)
,_iy(iy)
{
cout<<"Point(int ix=0,int iy=0)"<<endl;
}
~Point()
{
cout<<"~Point()"<<endl;
}
int getX() const
{
return _ix;
}
};
class Point3D
:protected Point
{
private:
int _iz;
public:
Point3D(int ix=0,int iy=0,int iz=0)
:Point(ix,iy)
,_iz(iz)
{
cout<<"Point3D(int ix=0,int iy=0,int iz=0)"<<endl;
}
~Point3D()
{
cout<<"~Point3D()"<<endl;
}
int getZ()const
{
return _iz;
}
void print() const
{
cout<<"ix ="<<getX()<<"iy ="<<_iy<<"iz ="<<_iz<<endl;
}
};
class Point4D
:public Point3D
{
private:
int _id;
public:
Point4D(int x=0,int y=0,int z=0,int d=0)
:Point3D(x,y,z)
,_id(d)
{
cout<<"Point4D(int x=0,int y=0,int z=0,int d=0)"<<endl;
}
~Point4D()
{
cout<<"~Point4D()"<<endl;
}
void print()const
{
cout<<"_ix = "<<getX()<<endl<<"_iy = "<<_iy<<endl //error
<<"_iz = "<<getZ()<<endl<<"_id = "<<_id<<endl;
}
};
int main()
{
Point4D P(1,2,3,4);
P.print();
return 0;
}
四.基类(父类)数据成员的初始化
在创建派生类(子类)对象的时候,在调用派生类(子类)构造函数的基础上,会先调用基类(父类)的构造函数对吸收继承的成员初始化,然后在继续调用派生类(子类)的构造函数初始化。
当创建派生类对象时,会调用派生类的构造函数,为了完成从基类吸收继承的数据成员初始化,如果在派生类初试化参数列表没有显示调用基类的构造函数编译器会自动调用基类的无参构造函数,若基类没有无参构造函数,那么程序就会报错。如果派生类需要调用有参构造函数,那么基类必须要有该构造函数。