一,为什么需要继承
目的:提高代码重用,提高i开发效率。例如我们已经拥有了制作某一零件的整套设备,以这套设别为基础之上,通过改造这个设备以实现其他种零件的制作,省去了从新研发等的时间。类比于c++语言中,就是通过实现继承该类并改造,实现其他功能。
二,继承的基本概念
c++最重要的特征是代码重用,通过继承机制可以利用已有的数据类型来定义新的数据类型,新的类不 仅拥有旧类的成员,还拥有新定义的成员。 一个B类继承于A类,或称从类A派生类B。这样的话,类A成 为基类(父类), 类B成为派生类(子类)。
派生类中的成员,包含两大部分: 一类是从基类继承过来 的,一类是自己增加的成员。 从基类继承过过来的表现其共性,而新增的成员体现了其个性。
如图所示:
例如给定一个基类,我们可理解为是一个父亲类,在继承父亲类的某些功能,定义的新类也就是派生类(这里可当作子类),子类除了继承以外的功能,还有自己的一些功能。
三,派生类的定义
我们通常这样定义子类(派生类),在有基类的前提下,定义子类在类定义的基本方式下,还需在后添加:继承方式 基类名
class 父类{}; class 子类:继承方式 父类名 { //新增子类数据 };
这里的继承方式就是所谓基类中的public,private ,protected中的类型的成员,一般这里我们是使用公共继承的。
如图以下的三种继承方式:
继承方式决定他们可以继承过来成员在派生类中是什么类型的,故我们可以知道,任何父类都不能将私有类型数据通过继承给予子类。如下:
#include<iostream> using namespace std; //定义基类 class Base { private: int a; protected: int b; public: int c; }; //定义派生类 class Son :public Base { public: void fun() { cout << b << c << endl; //cout<<a<<endl;不可访问 } }; int main() { Son a; // cout <<a.b<< endl;//不可访问 cout << a.c<< endl; a.fun(); return 0; }
很显然如果是公有继承过来,b还是保护型的,对于私有的直接是无法继承,所以这里的b是无法访问的。
四,继承中的析构预构造
1,子类中的构造与析构的顺序
对于派生类中的构造与析构的顺序看可用下图展示:
即构造时:先构造父类,再构造对象中的构造函数,最后才是子类的构造,而析构就是与之相反。
如下:
class Base { public: Base() { cout << "父类构造" << endl; } ~Base() { cout << "父类析构" << endl; } }; class member { public: member() { cout << "对象构造" << endl; } ~member() { cout << "对象析构" << endl; } }; class Son :public Base { public: member a; Son() { cout << "子类构造" << endl; } ~Son() { cout << "子类析构" << endl; } }; int main() { Son p; return 0; }
我们可以看到构造与析构的顺序。
2,子类调用成员对象,父类的有参构造
子类实例化对象时会自动调用成员对象、父类的默认构造。
子类实例对象时必须使用初始化列表 调用成员对象、父类的有参构造。(无参构造就不需要)
初始化列表时:父类写类名称 成员对象用对象名。
class Base { public: Base() { cout << "父类构造" << endl; } Base(int a) { cout << "父类有参构造" << endl; x = a; } ~Base() { cout << "父类析构" << endl; } int x; }; class member { public: member() { cout << "对象构造" << endl; } member(int a) { cout << "对象有参构造" << endl; y = a; } ~member() { cout << "对象析构" << endl; } int y; }; class Son :public Base { public: member a; int c; Son() { cout << "子类构造" << endl; } Son(int a, int b, int c) :Base(a), a(b)//初始化列表,基类用基类名显式调用,而对象调用用对象名么人不是类名 { this->c = c; cout << "Son有参构造" << endl; } ~Son() { cout << "子类析构" << endl; } }; int main() { Son p(10,20,30); return 0; }
注意初始化列表中基类与成员的构造调用!!
五,子类与父类的同名处理
我们先给出最实用的方法:
同名成员最简单最安全的处理方式:加作用域
1.子类和父类 同名成员数据
子类默认优先访问子类的同名成员
必须加父作用域 访问父类的同名成员。
class Base { public: int a; public: Base(int a) { this->a = a; } }; class son :public Base { public: int a; son(int x, int y) :Base(x) { a = y; } }; //这里同名,但优先是子类成员 int main() { son a(10, 20); cout << a.a <<endl;//20 //给a加上作用域 cout << a.Base::a << endl;//10 }
2.子类和父类 同名成员函数
class Base { public: void fun() { cout << "调用基类中fun" << endl; } int a; }; class son :public Base { public: void fun() { cout << "调用派生类中fun" << endl; } }; //这里同名,但优先是子类成员 int main() { son a; a.fun(); a.Base::fun(); return 0; }