首页 > 学院 > 开发设计 > 正文

继承和派生

2019-11-06 08:21:46
字体:
来源:转载
供稿:网友

本章内容为coursera课程C++程序设计中第五周的课件的整理

一、继承和派生

继承和派生的概念

继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),

那么就可以把A作为一个基类,而把B作为基类的一个派生类(也称子类)。派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量

和成员函数。

派生类一经定义后,可以独立使用,不依赖于基类。

派生类拥有基类的全部成员函数和成员变量,不论是PRivate、 protected、 public 。

在派生类的各个成员函数中,不能访问基类中的private成员。

需要继承机制的例子所有的学生都有的共同属性:姓名、学号、性别、成绩所有的学生都有的共同方法(成员函数):是否该留级、是否该奖励而不同的学生,又有各自不同的属性和方法:

研究生:导师、系大学生:系中学生:竞赛特长加分

如果为每类学生都从头编写一个类,显然会有不少重复的代码,浪费。比较好的做法是编写一个“学生”类,概括了各种学生的共同特点,

然后从“学生”类派生出“大学生”类,“中学生”类,“研究生类”。

派生类的写法:

class 派生类名: public 基类名{};
class CStudent {private:string sName;int nAge;public:bool IsThreeGood() { };void SetName( const string & name ){ sName = name; }//......};class CUndergraduateStudent: public CStudent {private:int nDepartment;public:bool IsThreeGood() { ...... }; //覆盖bool CanBaoYan() { .... };}; // 派生类的写法是:类名: public 基类名class CGraduatedStudent:public CStudent {private:int nDepartment;char szMentorName[20];public:int CountSalary() { ... };};

派生类对象的内存空间

派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。 在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。

class CBase{int v1,v2;};class CDerived:public CBase{int v3;};继承实例程序:学籍管理 

#include <iostream>#include <string>using namespace std;class CStudent {private:string name;string id; //学号char gender; //性别,'F'代表女, 'M'代表男int age;public:void PrintInfo();void SetInfo( const string & name_,const string & id_,int age_, char gender_ );string GetName() { return name; }};class CUndergraduateStudent:public CStudent{//本科生类,继承了CStudent类private:string department; //学生所属的系的名称public:void QualifiedForBaoyan() { //给予保研资格cout << “qualified for baoyan” << endl;}void PrintInfo() {CStudent::PrintInfo(); //调用基类的PrintInfocout << “Department:” << department <<endl;}void SetInfo( const string & name_,const string & id_,int age_,char gender_ ,const string & department_) {CStudent::SetInfo(name_,id_,age_,gender_); //调用基类的SetInfodepartment = department_;}};void CStudent::PrintInfo(){cout << "Name:" << name << endl;cout << "ID:" << id << endl;cout << "Age:" << age << endl;cout << "Gender:" << gender << endl;}void CStudent::SetInfo( const string & name_,const string & id_,int age_,char gender_ ){name = name_;id = id_;age = age_;gender = gender_;}1int main(){CUndergraduateStudent s2;s2.SetInfo(“Harry Potter ”, “118829212”,19,‘M’,“Computer Science”);cout << s2.GetName() << “ ” ;s2.QualifiedForBaoyan ();s2.PrintInfo ();return 0;}输出结果:Harry Potter qualified for baoyanName:Harry PotterID:118829212Age:19Gender:MDepartment:Computer Science

二、基类/派生类同名成员与Protected关键字基类和派生类有同名成员的情况

class base {int j;public:int i;void func();};
class derived : public base{public:int i;void access();void func();}
void derived::access(){j = 5; //error 因为j是基类的私有成员,派生类不能访问i = 5; //引用的是派生类的 ibase::i = 5; //引用的是基类的 ifunc(); //派生类的base::func(); //基类的}
derived obj;obj.i = 1;obj.base::i = 1;访问范围说明符基类的private成员: 可以被下列函数访问• 基类的成员函数• 基类的友员函数基类的public成员: 可以被下列函数访问• 基类的成员函数• 基类的友员函数• 派生类的成员函数• 派生类的友员函数• 其他的函数

访问范围说明符: protected

基类的protected成员: 可以被下列函数访问• 基类的成员函数• 基类的友员函数• 派生类的成员函数可以访问当前对象的基类的保护成员

class Father {private: int nPrivate; //私有成员public: int nPublic; //公有成员protected: int nProtected; // 保护成员};class Son : public Father {void AccessFather () {nPublic = 1; // ok;nPrivate = 1; // wrongnProtected = 1; // OK, 访问从基类继承的protected成员Son f;f.nProtected = 1; //wrong, f不是当前对象}};int main(){Father f;Son s;f.nPublic = 1; // Oks.nPublic = 1; // Okf.nProtected = 1; // errorf.nPrivate = 1; // errors.nProtected = 1; //errors.nPrivate = 1; // errorreturn 0;}三、派生类的构造函数

派生类对象包含基类对象,那么执行派生类构造函数之前, 先执行基类的构造函数。派生类交代基类初始化的具体形式:

构造函数名(形参表): 基类名(基类构造函数实参表){ }
class Bug {private :int nLegs; int nColor;public:int nType;Bug (int legs, int color);void PrintBug () { };};
class FlyBug: public Bug { // FlyBug是Bug的派生类int nWings;public:FlyBug(int legs, int color, int wings);};Bug::Bug( int legs, int color) {nLegs = legs;nColor = color;}//错误的FlyBug构造函数:FlyBug::FlyBug (int legs, int color, int wings) {nLegs = legs; // 不能访问nColor = color; // 不能访问nType = 1; // oknWings = wings;}//正确的FlyBug构造函数:FlyBug::FlyBug (int legs, int color, int wings):Bug(legs, color) {nWings = wings;}int main() {FlyBug fb ( 2,3,4);fb.PrintBug();fb.nType = 1;fb.nLegs = 2 ; // error.nLegs is privatereturn 0;}

FlyBug fb (2,3,4);在创建派生类的对象时,• 需要调用基类的构造函数:初始化派生类对象中从基类继承的成员• 在执行一个派生类的构造函数之前,总是先执行基类的构造函数调用基类构造函数的两种方式• 显式方式:派生类的构造函数中的基类的构造函数提供参数derived::derived(arg_derived-list):base(arg_base-list)• 隐式方式:派生类的构造函数中,省略基类构造函数时派生类的构造函数,自动调用基类的默认构造函数派生类的析构函数被执行时, 执行完派生类的析构函数后,自动调用基类的析构函数

class Base {public:int n;Base(int i):n(i){ cout << "Base " << n << " constructed" << endl; }~Base(){ cout << "Base " << n << " destructed" << endl; }};class Derived:public Base {public:Derived(int i):Base(i){ cout << "Derived constructed" << endl; }~Derived(){ cout << "Derived destructed" << endl; }};int main() { Derived Obj(3); return 0; } 输出结果:Base 3 constructedDerived constructedDerived destructedBase 3 destructed

包含成员对象的派生类的构造函数

class Skill {public:Skill(int n) { }};class FlyBug: public Bug {int nWings;Skill sk1, sk2;public:FlyBug(int legs, int color, int wings);};FlyBug::FlyBug( int legs, int color, int wings):Bug(legs, color), sk1(5), sk2(color) {nWings = wings;}创建派生类的对象时,执行派生类的构造函数之前:• 调用 基类 的构造函数: 初始化派生类对象中从基类继承的成员• 调用 成员对象类 的构造函数: 初始化派生类对象中成员对象执行完 派生类的析构函数 后:• 调用 成员对象类 的析构函数• 调用 基类 的析构函数析构函数的调用顺序与构造函数的调用顺序相反四、public继承的赋值兼容规则

class base { };class derived : public base { };base b;derived d;1) 派生类的对象可以赋值给基类对象b = d;  //可以想到:会把派生类对象d中的包含的基类对象赋值给基类对象b//反过来d=b;不可以!不可以把基类对象赋值在派生类对象。2) 派生类对象可以初始化基类引用base & br = d;3) 派生类对象的地址可以赋值给基类指针base * pb = & d;class base { };class derived : public base { };base b;derived d;• 如果派生方式是 private或protected,则上述三条不可行。

直接基类和间接基类类A派生类B,类B派生类C,类C派生类D, ……– 类A是类B的直接基类– 类B是类C的直接基类,类A是类C的间接基类– 类C是类D的直接基类,类A、 B是类D的间接基类

在声明派生类时, 只需要列出它的直接基类– 派生类沿着类的层次自动向上继承它的间接基类– 派生类的成员包括• 派生类自己定义的成员• 直接基类中的所有成员• 所有间接基类的全部成员

#include <iostream>using namespace std;class Base {public:int n;Base(int i):n(i) {cout << "Base " << n << " constructed" << endl;}~Base() {cout << "Base " << n << " destructed" << endl;}};class Derived:public Base{public:Derived(int i):Base(i) {cout << "Derived constructed" << endl;}~Derived() {cout << "Derived destructed" << endl;}};class MoreDerived:public Derived {public:MoreDerived():Derived(4) {cout << "More Derived constructed" << endl;}~MoreDerived() {cout << "More Derived destructed" << endl;}};int main(){MoreDerived Obj;return 0;}输出结果:Base 4 constructedDerived constructedMore Derived constructedMore Derived destructedDerived destructedBase 4 destructed


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表