C++实验二 继承与派生

实验二  继承与派生

一、实验目的

  1. 理解继承的概念、特性及在 C++语言中的实现方法;
  2. 掌握 C++语言派生类的声明与定义方法;
  3. 熟悉不同的继承方式(派生方式)的访问特性
  4. 掌握派生类构造函数的定义以及在定义、释放派生类对象时构造函数、析构函数的执行顺序;
  5. 学习虚基类在解决二义性问题中的作用

二、实验内容

㈠ 验证及认知实验

按要求调试下列程序,并回答相关问题。

程序 1:

#include<iostream>

using namespace std;

 class Base            //基类Base的定义

 { private:

      float x,y;

   public:

     Base(float a=0,float b=0)

     {x=a;y=b;}

     void print(void)

      { cout<<"x="<<x<<"  y="<<y;}

 };

class Derived:public Base     //派生类Derived的定义(注意定义方法 )

 { private:

      float z;

   public:

      Derived(float a=0,float b=0,float c=0):Base(a,b)

         { z=c;}        //派生类的构造函数定义

      void print(void)  //派生类的成员函数

         { Base::print();//调用基类 Base 的成员函数 print();

           cout<<"  z="<<z;

            }

};

int  main(void)

{ Base a(10.0,20.0);

  Derived b(10.0,20.0,30.0);

  a.print();

   cout<<endl;

  b.print();

  cout<<endl;

  b.Base::print();

  cout<<endl;

  return 0;

 }

问题:

  •  运行程序的输出结果为:

x=10  y=20

x=10  y=20  z=30

x=10  y=20

  • 程序中“a.print( );”调用的是____基类Base_______类成员中的“print()”成员函数,“b.print( );”调用的是____ 继承类Derived ___类成员中的“print()”成员函数,“b.Base::print();”调用的是____基类Base ___类成员中的“print()”成员函数。
  • 构造函数“Derived(float a=0,float b=0,float c=0):Base(a,b)”中的“Base(a,b)”的作用 是:_____调用基类Base的构造函数____________
  •  将派生类定义中的“public”改为“private”,重新编译程序,程序中__b.Base::print();____语句会出现编译错,其原因是__“Base”是“Derived”的不可访问的基类__。

(二)知识应用实验

分析下列程序,先写出程序的输出结果,再上机运行程序验证其正确性,如果不正确,请认真分析出错原因。

(1)程序2:

#include<iostream>

  using namespace std;

  class Base

  { private:

       float x,y;

    public:

       Base(float a=0,float b=0)

       {x=a;y=b;

         cout<<"基类构造函数被调用!\n";}

       ~Base()

          {cout<<"基类析构函数被调用!\n";}

       void print(void)

           { cout<<"x="<<x<<"  y="<<y;}

  };

class Derived:public Base

 { private:

      float z;

   public:

      Derived(float a=0,float b=0,float c=0):Base(a,b)

       { z=c;

         cout<<"派生类构造函数被调用!\n";  }

       ~Derived()

       {cout<<"派生类析构函数被调用!\n";}

      void print(void)

       { Base::print();

         cout<<"  z="<<z;

 }

     };

 int  main(void)

     { Base a(10.0,20.0);

       Derived b(10.0,20.0,30.0);

        a.print();

         cout<<endl;

         b.print();

         cout<<endl;

}

你分析的程序运行结果是:

基类构造函数被调用!

派生类构造函数被调用!

基类构造函数被调用!

基类构造函数被调用!

X=10 y=10

X=10 y=10 z=30

派生类析构函数被调用!

基类析构函数被调用!

程序的实际输出结果是:

基类构造函数被调用!

基类构造函数被调用!

派生类构造函数被调用!

x=10  y=20

x=10  y=20  z=30

派生类析构函数被调用!

基类析构函数被调用!

基类析构函数被调用!

请解释原因:

派生类构造函数中的某些初始化可能是基于基类的,所以规定构造在类层次的最根处开始。而在每一层,首先调用基类构造函数,然后调用成员对象构造函数。

因为C++的成员变量是不会自动初始化的。

而析构相反:因为先析构外面的派生类才能析构里面的基类?

总结:如图,从内往外构造,从外向内析构。

(2)程序3:

#include<iostream>

using namespace std;

class Data

{ private:

    int da;

  public:

    Data(int x=0)

     { da=x;

       cout<<" Data 类的构造函数被调用!"<<endl;  }

    ~Data()

     { cout<<" Data 类的析构函数被调用!"<<endl;}

     };

     class A

     { private :

         int a;

       public :

          A(int x=0)

           { a=x;

             cout<<" A 类的构造函数被调用!"<<endl;  }

          ~A()

           { cout<<" A 类的析构函数被调用!"<<endl;}

           };

     class B : public A

         { private :

              int b;

              Data c;

           public :

              B(int x=0,int y=0,int z=0):A(x),c(y)

               { b=z;

                cout<<" B 类的构造函数被调用!"<<endl;

                 }

              ~B()

               { cout<<" B 类的析构函数被调用!"<<endl;}

               };

int main()

   { B a;}

你分析的程序输出结果是:

A类的构造函数被调用!

 Data 类的构造函数被调用!

 B 类的构造函数被调用!

 B 类的析构函数被调用!

 Data 类的析构函数被调用!

 A 类的析构函数被调用!

程序的实际输出结果是:

 A类的构造函数被调用!

 Data 类的构造函数被调用!

 B 类的构造函数被调用!

 B 类的析构函数被调用!

 Data 类的析构函数被调用!

 A 类的析构函数被调用!

请解释原因:

1、构造函数的调用顺序

基类构造函数、对象成员构造函数、派生类本身的构造函数

2、析构函数的调用顺序

派生类本身的析构函数、对象成员析构函数、基类析构函数(与构造顺序正好相反)

(3)完善、调试通过下列程序,并按所要求回答问题。

//程序4

#include<iostream>

using namespace std;

 class Base      //基类 Base 的定义

  { private: 

      float x,y;

    public:

      Base(float a=0,float b=0)

       {x=a;y=b;}

      void setBase(float a=0,float b=0)

       {x=a;y=b;}

      void print(void)

       { cout<<"x="<<x<<"\ny="<<y<<endl;}

       };

 class Derived:public Base  //派生类 Derived 的定义

   { private:

        float z;

     public:

        Derived(    (1)    ):   (2) 

          { z=c;  }   //派生类的构造函数定义

        void setDerived(  (3) )

          { (4)  ;z=c;}

        void print(void)  //派生类的成员函数

          { Base::print();//调用基类 Base 的成员函数 print();

            cout<<"z="<<z<<endl;

             }

   };

 int main(void)

 { Derived b(10.0,20.0,30.0);

   b.print();

   b.setDerived(15.5,25.5,35.5);

   b.print();

   }

程序中:(1)处应改为 float a=0,float b=0,float c=0

       (2)处应改为 Base(a,b)

       (3)处应改为 float a=0,float b=0,float c=0

       (4)处应改为 Base::setBase(a,b)

                                     

(三)程序设计实验

1、已有类Time和Date,要求设计一个派生类Birthtime,它继承Time和Date,并且增加一个数据成员Childname 用于表示小孩的名字,同时设计主程序显示一个小孩的出生时间和名字。

class Time

   {public:

       Time (int  h, int m,int s)

       {

           hours=h;

           minutes=m;

           seconds=s;

       }

       void display()

       {

           cout<<"出生日期"<<hours<<"时"<<minutes<<"分"<<seconds<<"秒"<<endl;

       }

   protected:

    int hours,minutes,seconds;

    };

   class Date

   {public:

       Date  (int  m, int d,int y)

       {

           month=m;

           day=d;

           year=y;

       }

       void display()

       {

           cout<<"出生年月"<<year<<"年"<<month<<"月"<<day<<"日"<<endl;

       }

   protected:

    int month,day,year;

    };

(1) 类之间的继承关系图

(2)写出类的设计思路

设计一个派生类Birthtime,它继承Time和Date,并且增加一个(private) Childname数据成员用于表示小孩的名字,然后建立一个(public) display()函数进行名字的输出。

(3)完整代码

#include<iostream>

using namespace std;

class Time

   {public:

       Time (int h,int m,int s)

       {

           hours=h;

           minutes=m;

           seconds=s;

       }

       void display()

       {

           cout<<"出生日期"<<hours<<"时"<<minutes<<"分"<<seconds<<"秒"<<endl;

       }

   protected:

    int hours,minutes,seconds;

    };

class Date

   {public:

       Date  (int  m, int d,int y)

       {

           month=m;

           day=d;

           year=y;

       }

       void display()

       {

           cout<<"出生年月"<<year<<"年"<<month<<"月"<<day<<"日"<<endl;

       }

   protected:

    int month,day,year;

    };

class Birthtime:public Date,public Time

{

    private:

    string Childname;

    public:

        Birthtime(int a,int b,int c,int d,int e,int f,string g):Date(a,b,c),Time(d,e,f)

        {

            Childname=g;

        }

        void display()

       {

           cout<<"名字"<<Childname<<endl;

       }

};

int main(){

    Birthtime baby(06,03,2002,12,01,00,"小q");

    baby.display();

    baby.Date::display();

    baby.Time::display();

}

(4)运行结果

   2、设计职员类,它继承了Person类并组合了Date类。编写主程序显示职员数据如下:

姓名:杨萍

出生日期: 1988.10.6

性别:女

工作部门:团委

职务:团委书记

工资:6000

要求:画出类之间的继承关系图;写出类的设计思路;完整代码。

(1) 类之间的继承关系图

(2)写出类的设计思路

设计职员类,它继承了Person类并组合了Date类:

Person类中有数据成员姓名、性别,以及它们的显示函数,有参构造函数。

Date类中有数据成员年、月、日,显示函数,有参构造函数。

Employee类继承了Person类并组合了Date类(含有一个Date类对象数据成员),并增加了数据成员工作部门职务工资,显示函数,有参构造函数。

(3)完整代码

#include <iostream>

using namespace std;

class Person//继承Person类

{

private:

    string name;//姓名

    string sex;//性别

public:

    Person(string n,string s){

    name=n;

    sex=s;

    }

    void getname(){

    cout<<"姓名:"<<name<<endl;

    }

    void getsex(){

    cout<<"性别:"<<sex<<endl;

    }

};

class Date//组合Date类

   {public:

       Date  (int  y, int m,int d)

       {

           year=y;

           month=m;

           day=d;

       }

       void getdate()

       {

           cout<<"出生日期: "<<year<<"."<<month<<"."<<day<<endl;

       }

   protected:

    int month,day,year;

    };

class Employee:public Person{

private:

    string department;//部门

    string office;//职位

    float salary;//工资

public:

    Date date;//日期

    Employee(string n,string s,int  y, int m,int d,string de,string o,float sa):Person(n,s),date(y,m,d)

    {

        department=de;

        office=o;

        salary=sa;

    }

    void getemployee(){

    cout<<"工作部门:"<<department<<endl;

    cout<<"职务:"<<office<<endl;

    cout<<"工资:"<<salary<<endl;

    }

};

int main()

{

    Employee em("杨萍","女",1988,10,6,"团委","团委书记",6000);

    em.getname();

    em.date.getdate();

    em.getsex();

    em.getemployee();

    return 0;

}

(4)运行结果

三、实验收获与创新

收获:

1.弄清楚了继承类本身、对象成员、基类的构造函数、析构函数调用顺序

2.明白了继承和组合的关系

3.知道了当继承不同类的成员函数同名时如何进行调用

4.熟悉不同的继承方式(派生方式)的访问特性

创新:

1.通过调试试验发现多继承类调用基类的构造函数、析构函数只与声明顺序有关,与其他无关

2...

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值