类的继承
一:基类和派生类❤❤❤
•类的继承就是从现有类的基础上,派生出一个新的类,新派生的类自动具有了现有类的全部的属性和特征,所以可以说新类继承了原有的类;同时,新类还加入了原来的类所没有的、新的属性和特征,所以又可以说新类是对原有类的扩展。
•在继承关系中,通常把被继承的类称为基类或父类,而把通过继承产生的新类称为派生类或子类。
•基类和派生类的关系是相对而言的,一个派生类也可以成为另一个类的基类。在实际的程序设计中,通常需要通过继承和派生构建具有层次结构的类家族。
二:派生类的定义❤❤❤
class 派生类名:继承属性 基类1,…… ,继承属性 基类n
{
成员定义表
};
通过继承,派生类自动拥有了基类的所有成员(除了基类的构造函数和析构函数),在派生类的类体中,只需声明属于派生类的成员。
三:继承类型
-
单一继承
-
多级继承
-
多重继承
-
层次继承
四:继承方式
派生类的成员函数是可以访问公有成员和保护成员的
公有继承:❤
(1)不可访问基类的私有成员
(2)基类的公有成员和保护成员在派生类中属性不变
(3)只有基类的公有成员才能被派生类对象访问
(4)基类的公有成员和保护成员均可以被派生类的成员函数访问
#include<iostream>
using namespace std;
class Box
{ private:
int length;
protected:
int width;
public:
int height;
void SetLength(int l) { length=l; }
void SetWidth(int w) { width=w; }
void show()
{ cout<<"l="<<length<<" w="<<width<<" h="
<<height<<endl;
}
class ColorBox: public Box
{
int color;
public:
void SetColor(int c) { color=c; }
void ShowColor()
{
cout<<"c="<<color<<endl;
// cout<<“l=”<<length<<endl; /*错误,不能访问基类私有成员*/ }
};
int main()
{
ColorBox ob;
ob.SetLength(10);
ob.SetWidth(20);
ob.height=30;
ob.SetColor(100);
// ob.width=3; //错误,对象不能访问保护成员
ob.show();
ob.ShowColor();
return 0;
}
私有继承:❤
(1)不可访问基类的私有成员
(2)基类的公有成员和保护成员均为派生类的私有成员
(3)基类的所有成员不能被派生类对象访问
(4)基类的公有成员和保护成员均可以被派生类的成员函数访问,无法继续被继承
保护继承❤
(1)不可访问基类的私有成员
(2)基类的公有成员和保护成员均为派生类的保护成员
(3)基类的所有成员不能被派生类对象访问
(4)基类的公有成员和保护成员均可以被派生类的成员函数访问,可以继续向下继承
五:类型转换规则
-
一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。具体表现在:
-
派生类的对象可以隐含转换为基类对象。基类对象a=b(派生类对象)
-
派生类的对象可以初始化基类的引用。基类指针对象a=&b(派生类对象)
-
派生类的指针可以隐含转换为基类的指针。
-
转换后只能使用从基类继承的成员
#include <iostream>
using namespace std;
class Base1 { //基类Base1定义
public:
void display() const {
cout << "Base1::display()" << endl;
}
};
class Base2: public Base1 { //公有派生类Base2定义
public:
void display() const {
cout << "Base2::display()" << endl;
}
};
class Derived: public Base2 { //公有派生类Derived定义
public:
void display() const {
cout << "Derived::display()" << endl;
}
};
void fun(Base2 *ptr) { //参数为指向基类对象的指针
ptr->display(); //"对象指针->成员名"
}
int main() { //主函数
Base1 base1; //声明Base1类对象
Base2 base2; //声明Base2类对象
Derived derived; //声明Derived类对象
//fun(&base1); //用指向Base1对象的指针调用fun函数
fun(&base2); //用指向Base2对象的指针调用fun函数
fun(&derived); //用指向Derived对象的指针调用fun函数
return 0;
}
六:派生类的构造函数
-
原则:仍然是自己的事情自己做。
-
u基类的构造函数不被继承,派生类中需要声明自己的构造函数。
-
u定义构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化,自动调用基类构造函数完成。
❤❤❤u派生类的构造函数需要给基类的构造函数传递参数,派生类构造函数使用初始化列表(冒号语法)向基类的构造函数传递参数。定义派生类构造函数的语法格式如下:
❤❤❤派生类名::派生类名(总参数列表):基类名1(参数列表1),基类名2(参数列表2),……
{初始化派生类的实例数据成员;}
B::B(int bb,int aa,int dd1,int dd2):A(aa),d(dd1,dd2)//A是一个类,而不是写对象
{ b=bb;
cout<<"执行构造函数B "<<b<<endl;
}
调用构造函数的顺序
派生类构造函数执行次序:
(1)调用基类构造函数(次序以派生类定义中基类定义顺序)
(2)调用组合类构造函数(次序以派生类定义中组合类定义顺序)
(3)执行派生类构造函数体