继承:一个类直接包含另一个类的属性和方法。
同类事物具有共同性,在同类事物中,每个事物又具有特殊性。运用抽象的原则舍弃对象的特殊性,抽取其共同性,则得到一个适应于一批对象的类,这就是基类(父类);
把具有特殊性的类称为派生类(子类)。派生类的对象拥有基类的全部或部分属性与方法,称作派生类对基类的继承。
继承的方式有三种:公有继承,私有继承和保护继承
通过一个列子,体会不同的继承方式对类的成员函数的影响:
class CFruit //声明基类
{
public:
void func1(); //成员函数
protected:
int x1; //保护数据成员
private:
int y1; //私有数据成员
};
class CApple:public CFruit //CApple类公共继承于CFruit类
{
public:
void func2(); //成员函数
protected:
int x2; //保护数据成员
private:
int y2; //私有数据成员
};
class COrange:private CFruit //COrange类私有继承于CFruit类
{
public:
void func3(); //成员函数
};
class CRichApple:public CApple//CRichApple类公共继承于CApple类
{
public:
void func4(); //成员函数
};
class CGrapefruit:public COrange//CGranpefruit类共有继承于COrange类
{
public:
void func5();
};
1、子类CApple中的成员函数func2,可以访问父类CFruit中的成员函数func1和数据成员x1,而不能访问数据成员y1;
2、子类COrange中的成员函数func3,和第一条相同;
3、子类CRichApple中的成员函数func4,可以访问CFruit中的成员函数func1,和CApple中的成员函数func2和数据成员x2,但不能访问CFruit的数据成员x1和y1和CApple的数据成员y2;
4,子类CGrapefruit中的成员函数func5,不能访问CFruit中的任何成员,但可以访问COrange中的成员函数func3.
子类的构造函数:
要实现子类的构造函数,除了对子类自己的数据成员进行初始化,还必须负责调用父类的构造函数来使父类的数据成员得到初始化。初始化父类的数据成员,必须采用初始化成员列表的方式进行,如果子类中还有子对象,则还应包含子对象的初始化。
子类构造函数的调用顺序为 先调用父类构造函数,再调用子类构造函数
通过一个程序例子来体会:
#include <iostream>
#include <fstream>
using namespace std;
class CPoint
{
public:
CPoint();
CPoint(int x,int y);
void disp();
void getXY(int &x,int &y);
private:
int m_x;
int m_y;
};
CPoint::CPoint()
{
m_x=0;
m_y=0;
cout<<"调用CPoint的默认构造函数"<<endl;
}
CPoint::CPoint(int x,int y)
{
m_x=x;
m_y=y;
cout<<"调用CPoint的构造函数"<<endl;
}
void CPoint::getXY(int &x,int &y)
{
x=m_x;
y=m_y;
}
void CPoint::disp()
{
cout<<m_x<<","<<m_y<<endl;
}
class C3DPoint:public CPoint //声明子类C3DPoint继承于CPoint类
{
public:
C3DPoint();
C3DPoint(int x,int y,int z);
void disp();
private:
CPoint p;
int m_z;
};
C3DPoint::C3DPoint():CPoint() //调用父类的默认构造函数
{
m_z=0;
cout<<"调用C3CPoint默认构造函数"<<endl;
}
C3DPoint::C3DPoint(int x,int y,int z):CPoint(x,y),p(x,y)//(使用初始化成员列表的方式)调用父类的构造函数,并初始化子对象
{
m_z=z;
cout<<"调用C3CPoint构造函数"<<endl;
}
void C3DPoint::disp()
{
int x=0,y=0;
p.getXY(x,y);
cout<<x<<","<<y<<","<<m_z<<endl;
}
int main()
{
C3DPoint point3d1,point3d2(50,80,10);
CPoint p(20,30);
p.disp();
point3d1.disp();
point3d2.disp();
return 0;
}
从代码的输出结构可以看出,子类的对象point3d不仅可以实现父类对象p的全部功能,而且还增加了新的功能,实现了z轴坐标的输出。
子类的析构函数,调用过程是:先调用子类的析构函数,再调用父类的析构函数。
子类的类型适应:
基类对象的指针和引用可以代表派生类对象的指针和引用。但是子类的指针和引用并不能代表父类的对象指针和引用,否则会产生编译错误。
多继承:
一个子类对多个父类的关系:
例子:多继承的子类构造函数示例:
#include <iostream>
#include <fstream>
using namespace std;
class CAnimal
{
public:
CAnimal(){m_age=0;}
CAnimal(int age);
void disp();
private:
int m_age;
};
CAnimal::CAnimal(int age)
{
m_age=age;
cout<<"调用CAnimal的构造函数"<<endl;
}
void CAnimal::disp()
{
cout<<m_age<<",";
}
class CMammal
{
public:
CMammal(){m_latex=0;}
CMammal(int latex);
int getNum(){return m_latex;}
void disp();
private:
int m_latex;
};
CMammal::CMammal(int latex)
{
m_latex=latex;
cout<<"调用CMammal的构造函数"<<endl;
}
void CMammal::disp()
{
cout<<m_latex<<",";
}
class CMonkey:public CAnimal,public CMammal //共有多继承于CAnimal和CMammal
{
public:
CMonkey(int age,int latex,int a,int tail);
void print();
private:
CMammal mammal;
int m_tail;
};
CMonkey::CMonkey(int age,int latex,int a,int tail):CMammal(latex),CAnimal(age),mammal(a) //类CMonkey构造函数,多继承的子类构造函数中,必须通过初始化成员列表调用多个父类的构造函数
{
m_tail=tail;
cout<<"调用CMonkey的构造函数"<<endl;
}
void CMonkey::print()
{
CAnimal::disp();
CMammal::disp();
cout<<mammal.getNum()<<","<<m_tail<<endl;
}
int main()
{
CMonkey monkey(10,20,30,40);
monkey.print();
return 0;
}
多继承中子类