上一节学习了C++的数组,指针和字符串,c++:-3。本节学习C++的继承与派生:
继承的目的:实现设计与代码的重用。
派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造。
(1)语法:
class 派生类名:继承方式 基类名{ 成员声明;}(2)例:
class Derived: public Base{ public: Derived (); ~Derived ();};(1)语法
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...{ 成员声明;}注意:每一个“继承方式”,只用于限制对紧随其后之基类的继承。
(2)例:
class Derived: public Base1, private Base2{ public: Derived (); ~Derived ();};(1)不同继承方式的影响主要体现在:
(2)有三种:公有继承、私有继承、保护继承
(1)继承的访问控制
(2)访问权限
(3)举例
//Point.h#ifndef _POINT_H#define _POINT_Hclass Point { //基类Point类的定义public: //公有函数成员 void initPoint(float x = 0, float y = 0){ this->x = x; this->y = y; } void move(float offX, float offY){ x += offX; y += offY; } float getX() const { return x; } float getY() const { return y; }private: //私有数据成员 float x, y;};#endif //_POINT_H//Rectangle.h#ifndef _RECTANGLE_H#define _RECTANGLE_H#include "Point.h"class Rectangle: public Point {//派生类定义部分public://新增公有函数成员 void initRectangle(float x, float y, float w, float h) { initPoint(x, y); //调用基类公有成员函数 this->w = w; this->h = h; } float getH() const { return h; } float getW() const { return w; }private://新增私有数据成员 float w, h;};#endif //_RECTANGLE_H//main.cpp#include <iostream>#include "Rectangle.h"using namespace std;int main() { Rectangle rect; //定义Rectangle类的对象 //设置矩形的数据 rect.initRectangle(2, 3, 20, 10); rect.move(3,2); //移动矩形位置 cout << "The data of rect(x,y,w,h): " << endl; //输出矩形的特征参数 cout << rect.getX() <<", " << rect.getY() << ", " << rect.getW() << ", " << rect.getH() << endl; return 0;}输出:The data of rect(x,y,w,h):5, 5, 20, 10(1)继承的访问控制
(2)访问权限
(3)举例:
//Point.h#ifndef _POINT_H#define _POINT_Hclass Point { //基类Point类的定义public: //公有函数成员 void initPoint(float x = 0, float y = 0) { this->x = x; this->y = y;} void move(float offX, float offY) { x += offX; y += offY; } float getX() const { return x; } float getY() const { return y; }private: //私有数据成员 float x, y;};#endif //_POINT_H//Rectangle.h#ifndef _RECTANGLE_H#define _RECTANGLE_H#include "Point.h"class Rectangle: private Point { //派生类定义部分public: //新增公有函数成员 void initRectangle(float x, float y, float w, float h) { initPoint(x, y); //调用基类公有成员函数 this->w = w; this->h = h; } void move(float offX, float offY) { Point::move(offX, offY); } float getX() const { return Point::getX(); } float getY() const { return Point::getY(); } float getH() const { return h; } float getW() const { return w; }private: //新增私有数据成员 float w, h;};#endif //_RECTANGLE_H//main.cpp#include <iostream>#include <cmath>#include "Rectangle.h"using namespace std;int main() { Rectangle rect; //定义Rectangle类的对象 rect.initRectangle(2, 3, 20, 10); //设置矩形的数据 rect.move(3,2); //移动矩形位置 cout << "The data of rect(x,y,w,h): " << endl; cout << rect.getX() <<", " //输出矩形的特征参数 << rect.getY() << ", " << rect.getW() << ", " << rect.getH() << endl; return 0;}(1)继承的访问控制
(2)访问权限
(3)protected 成员的特点与作用
(4)举例:单继承
class A {protected: int x;};class B: public A{public: void function();};void B::function() { x = 5; //正确,派生类成员函数可以访问}int main() { A a; a.x = 5;//错误,派生类对象可以访问}(5)举例:多继承
class A {public: void setA(int); void showA() const;private: int a;};class B {public: void setB(int); void showB() const;private: int b;};class C : public A, private B {public: void setC(int, int, int); void showC() const;private: int c;};void A::setA(int x) { a=x;}void B::setB(int x) { b=x;}void C::setC(int x, int y, int z) { //派生类成员直接访问基类的 //公有成员 setA(x); setB(y); c = z;}//其他函数实现略int main() { C obj; obj.setA(5); obj.showA(); obj.setC(6,7,9); obj.showC();// obj.setB(6); 错误,private继承的派生类对象类外不能访问// obj.showB(); 错误 return 0;}(1)公有派生类对象可以被当作基类的对象使用,反之则不可。
(2)通过基类对象名、指针只能使用从基类继承的成员。
(3)举例
#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(Base1 *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;}输出:Base1::display()Base1::display()Base1::display()(1)默认情况:
(2)C++11规定:
using B::B;派生类新增成员可以通过类内初始值进行初始化。
可用using语句继承基类构造函数。
但是只能初始化从基类继承的成员。
(3) 建议:
如果派生类有自己新增的成员,且需要通过构造函数初始化,则派生类要自定义构造函数。
(4)若不继承基类的构造函数
派生类新增成员:派生类定义构造函数初始化;
继承来的成员:自动调用基类构造函数进行初始化;
派生类的构造函数需要给基类的构造函数传递参数。
派生类只有一个直接基类的情况,是单继承。单继承时,派生类的构造函数只需要给一个直接基类构造函数传递参数。
(1)语法
派生类名::派生类名(基类所需的形参,本类成员所需的形参):基类名(参数表), 本类成员初始化列表{ //其他初始化;};(2)举例
#include<iostream>using namespace std;class B {public: B(); B(int i); ~B(); void print() const;private: int b;};B::B() { b=0; cout << "B's default constructor called." << endl;}B::B(int i) { b=i; cout << "B's constructor called." << endl;}B::~B() { cout << "B's destructor called." << endl;}void B::print() const { cout << b << endl;}class C: public B {public: C(); C(int i, int j); ~C(); void print() const;private: int c;};C::C() { c = 0; cout << "C's default constructor called." << endl;}C::C(int i,int j): B(i), c(j){ cout << "C's constructor called." << endl;}C::~C() { cout << "C's destructor called." << endl;}void C::print() const { B::print(); cout << c << endl;}int main() { C obj(5, 6); obj.print(); return 0;}输出:B's constructor called.C's constructor called.56C's destructor called.B's destructor called.多继承时,有多个直接基类,如果不继承基类的构造函数,派生类构造函数需要给所有基类构造函数传递参数。
(1)语法
派生类名::派生类名(参数表) : 基类名1(基类1初始化参数表), 基类名2(基类2初始化参数表), ...基类名n(基类初始化参数表), 本类成员初始化列表{ //其他初始化;};(2)派生类与基类的构造函数
当基类有默认构造函数时:
派生类构造函数可以不向基类构造函数传递参数。
构造派生类的对象时,基类的默认构造函数将被调用。
如需执行基类中带参数的构造函数
派生类构造函数应为基类构造函数提供参数。
(3)多继承且有对象成员时派生的构造函数定义
派生类名::派生类名(形参表):基类名1(参数), 基类名2(参数), ..., 基类名n(参数), 本类成员(含对象成员)初始化列表{ //其他初始化};(1)调用基类构造函数。
(2)对初始化列表中的成员进行初始化。
(3)执行派生类的构造函数体中的内容。
#include <iostream>using namespace std;class Base1 {//基类Base1,构造函数有参数public: Base1(int i) { cout << "Constructing Base1 " << i << endl; }};class Base2 {//基类Base2,构造函数有参数public: Base2(int j) { cout << "Constructing Base2 " << j << endl; }};class Base3 {//基类Base3,构造函数无参数public: Base3() { cout << "Constructing Base3 *" << endl; }};class Derived: public Base2, public Base1, public Base3 {public: Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c), Base2(b) //此处的次序与构造函数的执行次序无关 { }private: Base1 member1; Base2 member2; Base3 member3;};int main() { Derived obj(1, 2, 3, 4); return 0;}输出://先调用基类构造函数Constructing Base2 2Constructing Base1 1Constructing Base3 *//再对初始化列表中的成员进行初始化。Constructing Base1 3Constructing Base2 4Constructing Base3 *(1)派生类未定义复制构造函数的情况
(2)派生类定义了复制构造函数的情况
#include <iostream>using namespace std;class Base1 {public: Base1(int i) { cout << "Constructing Base1 " << i << endl; } ~Base1() { cout << "Destructing Base1" << endl; }};class Base2 {public: Base2(int j) { cout << "Constructing Base2 " << j << endl; } ~Base2() { cout << "Destructing Base2" << endl; }};class Base3 {public: Base3() { cout << "Constructing Base3 *" << endl; } ~Base3() { cout << "Destructing Base3" << endl; }};class Derived: public Base2, public Base1, public Base3 {public: Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c), Base2(b) { }private: Base1 member1; Base2 member2; Base3 member3;};int main() { Derived obj(1, 2, 3, 4); return 0;}输出://构造函数Constructing Base2 2Constructing Base1 1Constructing Base3 *Constructing Base1 3Constructing Base2 4Constructing Base3 *//析构函数Destructing Base3Destructing Base2Destructing Base1Destructing Base3Destructing Base1Destructing Base2访问从基类继承的成员
(1)当派生类与基类中有相同成员时:
(2)举例
#include <iostream>using namespace std;class Base1 {public: int var; void fun() { cout << "Member of Base1" << endl; }};class Base2 {public: int var; void fun() { cout << "Member of Base2" << endl; }};class Derived: public Base1, public Base2 {public: int var; void fun() { cout << "Member of Derived" << endl; }};int main() { Derived d; Derived *p = &d; //访问Derived类成员 d.var = 1; d.fun(); //访问Base1基类成员 d.Base1::var = 2; d.Base1::fun(); //访问Base2基类成员 p->Base2::var = 3; p->Base2::fun(); return 0;}输出:Member of DerivedMember of Base1Member of Base2如果从不同基类继承了同名成员,但是在派生类中没有定义同名成员,“派生类对象名或引用名.成员名”、“派生类指针->成员名”访问成员存在二义性问题
//7_7.cpp#include <iostream>using namespace std;class Base0 { //定义基类Base0public: int var0; void fun0() { cout << "Member of Base0" << endl; }};class Base1: public Base0 { //定义派生类Base1 public: //新增外部接口 int var1;};class Base2: public Base0 { //定义派生类Base2 public: //新增外部接口 int var2;};class Derived: public Base1, public Base2 {public: int var; void fun() { cout << "Member of Derived" << endl; }};int main() { //程序主函数 Derived d; d.Base1::var0 = 2; d.Base1::fun0(); d.Base2::var0 = 3; d.Base2::fun0(); return 0;}
当派生类从多个基类派生,而这些基类又共同基类,则在访问此共同基类中的成员时,将产生冗余,并有可能因冗余带来不一致性
以virtual说明基类继承方式
例:class B1:virtual public B

#include <iostream>using namespace std;class Base0 {public: int var0; void fun0() { cout << "Member of Base0" << endl; }};class Base1: virtual public Base0 {public: int var1;};class Base2: virtual public Base0 {public: int var2;};class Derived: public Base1, public Base2 {//定义派生类Derivedpublic: int var; void fun() { cout << "Member of Derived" << endl; }};int main() { Derived d; d.var0 = 2; //直接访问虚基类的数据成员 d.fun0(); //直接访问虚基类的函数成员 return 0;}举例:
#include <iostream>using namespace std;class Base0 {public: Base0(int var) : var0(var) { } int var0; void fun0() { cout << "Member of Base0" << endl; }};class Base1: virtual public Base0 {public: Base1(int var) : Base0(var) { } int var1;};class Base2: virtual public Base0 {public: Base2(int var) : Base0(var) { } int var2;};class Derived: public Base1, public Base2 {public: Derived(int var) : Base0(var), Base1(var), Base2(var) { } int var; void fun() { cout << "Member of Derived" << endl; }};int main() { //程序主函数 Derived d(1); d.var0 = 2; //直接访问虚基类的数据成员 d.fun0(); //直接访问虚基类的函数成员 return 0;}举例:Member of Base0(1)
#include <iostream>using namespace std;class Animal { //int age;public: int age;};class Dog : Animal {public: void SetAge(int n) {age = n;}};int main(){ Dog d; d.SetAge(2); return 0;}(2)
#include <iostream>using namespace std;class BaseClass {public: int Number; int getNumber() {return Number;} BaseClass(){ cout<<"BaseClass construct"<<endl;} ~BaseClass(){ cout<<"BaseClass destruct"<<endl;}};class DerivedClass : BaseClass {public: DerivedClass() { Number = 0; Number ++; cout << "DerivedClass Construction. Number = " << getNumber() << endl; } ~DerivedClass() { Number --; cout << "DerivedClass Destruction. Number = " << getNumber() << endl; }};int main(){ DerivedClass d; return 0;}说明:BaseClass constructDerivedClass Construction. Number = 1DerivedClass Destruction. Number = 0BaseClass destruct(3)
#include <iostream>using namespace std;class Vehicle{public: int MaxSpeed; int Weight; void Run(){cout<<"Vehicle run"<<endl;}; void Stop(){cout<<"Vehicle stop"<<endl;};};class Bicycle : virtual public Vehicle{public: int Height;};class Motorcar : virtual public Vehicle{public: int SeatNum;};class Motorcycle : public Bicycle, public Motorcar{};int main(){ Motorcycle m; m.Height=1; m.SeatNum=2; m.Weight=100; m.MaxSpeed=60; m.Run(); m.Stop(); return 0;}