【C++】阶段性总结(三)——继承和多态

继承

类之间的关系

继承

在已有类的基础上创建新类的过程

一个B类继承A类,或称从类A派生B类——A称为基类(父类),B称为派生类(子类)

基类和派生类

class 派生类名 : 基类名表
  {
        数据成员和成员函数声明
  };

基类名表 :

访问控制  基类名1, 访问控制  基类名2 ,… ,   访问控制  基类名n

注意:==种方式继承基类,派生类都不能直接使用基类的私有成员 ==

派生类的生成过程经历了三个步骤:

在这里插入图片描述

派生类的对象结构

在这里插入图片描述

公有继承

在这里插入图片描述
在这里插入图片描述
例题

定义一个基类person(不定义构造函数)
姓名、性别、年龄(访问权限设置为私有)
定义公有的成员函数set_p()
定义公有的成员函数display_p(),显示person的信息
再由基类派生出学生类(不定义构造函数,采用公有继承的方式)
增加学号、班级、专业和入学成绩
定义公有成员函数set_t()
定义成员函定义公有的成员函数display_s(),显示所有的信息
#include<iostream>
#include <string>
using namespace std;
class Person
{
 string name;
 int age;
 string sex;
public:
 void set_p() 
 {
  cout<<"name\tage\tsex"<<endl;
  cin>>name>>age>>sex;
 }
 void show_p() 
 {
   cout<<name<<"  "<<age<<"  "<<sex<<endl;
 }
};

方法一:

class student :public Person
{
 string no;
 string zhuanye;
 string t_class;
 float score;
public:
 void set_t()
 {
       set_p(); //调用继承于基类的成员函数访问继承于基类的私有数据成员
     cout<<"zhuanye\tt_class\tscore"<<endl;
     //cin>>zhuanye>>t_class>>score;//错误,没有输入基类继承过来的成员
     cin>>name>>age>>sex>>zhuanye>>t_class>>score;
     
 }
 void show_t() 
 {
  show_p();
  //cout<<zhuanye<<"  "<<t_class<<"  "<<score<<endl;//没有显示学号
  cout<<name<<"  "<<age<<"  "<<sex<<zhuanye<<"  "<<t_class<<"  "<<score<<endl;
 }
};

方法二:

class student :public Person
{
 string no;
 string zhuanye;
 string t_class;
 float score;       //设计自己成员
public:
        //改造基类成员 成员函数的覆盖
 void set()
 {    //隐藏了基类中的同名成员       
      Person::set(); //调用继承于基类的成员函数访问继承于基类的数据成员(首先调用基类函数)
         cout<<"zhuanye\tt_class\tscore"<<endl;
      cin>>zhuanye>>t_class>>score;
 }
 void show() 
 {
  Person::show();//不但显示自己成员,还显示基类成员  基类成员的使用
  cout<<zhuanye<<"  "<<t_class<<"  "<<score<<endl;
 }
};
重名成员

在这里插入图片描述

派生类中访问静态成员

在这里插入图片描述

基类初始化

在这里插入图片描述

例题
调用构造函数顺序测试,构造函数无参数

#include<iostream>
using namespace std ;
class  Base
{ 
 public :  
  Base ( ) { cout << "Base created.\n" ;  }
} ;
class  D_class : public  Base
{ 
 //派生类构造函数
 public : 
   D_class ( ) {  cout << "D_class  created.\n" ;  }
} ;
int main ( )
{
 D_class d1 ;//先调用基类构造函数再本身 
}
派生类构造函数

==派生类构造函数和析构函数的定义规则 ==
派生类构造函数和析构函数的使用原则

  1. 类的构造函数和析构函数不能被继承
  2. 如果基类没有定义构造函数或有无参的构造函数, 派生类也可以不用定义构造函数
  3. 如果基类无无参的构造函数,派生类必须定义构造函数
  4. 如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造
  5. 派生类是否定义析构函数与所属的基类无关

在这里插入图片描述

调用基类构造函数对基类成员进行初始化。

在这里插入图片描述

      派生类::派生类名(参数总表):基类名(参数表)
     {
             // 派生类新增成员的初始化语句
     }
派生类析构函数

在这里插入图片描述

继承的应用实例

在这里插入图片描述

class Point
{   friend ostream &operator<< (ostream &, const Point &);
  public:
    Point( int = 0, int = 0 ) ; // 带默认参数的构造函数
    void setPoint( int, int ) ; // 对点坐标数据赋值
    int getX() const { return x ; }     int getY() const { return y ; }
  protected:    int x, y; // Point类的数据成员
};
class Circle : public Point
{   friend ostream &operator<< (ostream &, const Circle &); // 友元函数
  public:
    Circle(double r=0.0, int x=0, int y=0); // 构造函数
    void setRadius(double);  /*置半径*/          double getRadius() const;     /*返回半径*/ 
    double area() const;  // 返回面积
  protected:    double radius; // 数据成员,半径
};
class Cylinder:public Circle
{    friend ostream & operator<<(ostream &, const Cylinder &);    // 友元函数
   public:
     Cylinder(double h=0.0, double r=0.0, int x=0, int y=0);      // 构造函数
     void setHeight(double);    /* 置高度值*/           double getHeight() const;     /* 返回高度值*/
     double area() const;      /* 返回面积*/            double volume() const;     /* 返回体积*/
   protected:     double height; // 数据成员,高度
};

多继承

在这里插入图片描述

class  派生类名 : 访问控制  基类名1 ,  访问控制  基类名2 ,, 访问控制  基类名n
    {
         数据成员和成员函数声明
    }

在这里插入图片描述

多继承的构造函数
派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),,基类名n(参数表n)
    {
           // 派生类新增成员的初始化语句
     } 

多继承方式下构造函数的执行顺序:

在这里插入图片描述

虚基类
  如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。

赋值兼容原则
赋值兼容规则指在程序中需要使用基类对象的任何地方,都可以用公有派生类的对象来替代。

在这里插入图片描述

虚函数和多态

 多态性(Polymorphism)是指一个名字,多种语义;或界面相同,多种实现。

在这里插入图片描述

静态联编

联编是指一个程序模块、代码之间互相关联的过程。
静态联编,是程序的匹配、连接在编译阶段实现,也称为早期匹配。
重载函数使用静态联编

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

类指针的关系

基类指针和派生类指针与基类对象和派生类对象4种可能匹配:

 直接用基类指针引用基类对象;
 直接用派生类指针引用派生类对象;
 用基类指针引用一个派生类对象;
 用派生类指针引用一个基类对象。 

虚函数和动态编联

冠以关键字 virtual 的成员函数称为虚函数

注意实现运行时多态的关键首先是要说明虚函数,另外,必须用
基类指针调用派生类的不同实现版本

基类指针虽然获取派生类对象地址,却只能访问派生类从基类继承的成员

#include<iostream>
using namespace std ;
class  Base
{ public :       Base(char xx)  { x = xx; }
                      void who()  { cout << "Base class: " << x << "\n" ; }
   protected:    char x;
} ;
class  First_d : public  Base
{ public :       First_d(char xx, char yy):Base(xx)  { y = yy; }
                      void who()  { cout << "First derived class: "<< x << ", " << y << "\n" ; }
   protected:    char y;
} ;
class  Second_d : public  First_d
{ public :
      Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } 
      void who()  { cout << "Second derived class: "<< x << ", " << y << ", " << z << "\n" ; }
   protected:    char z;
} ;
int main()
{ Base  B_obj( 'A' ) ;   First_d F_obj( 'T', 'O' ) ;  Second_d S_obj( 'E', 'N', 'D' ) ;
   Base  * p ;
   p = & B_obj ;    p -> who() ;
   p = &F_obj ;     p -> who() ;
   p = &S_obj ;     p -> who() ;
   F_obj.who() ;
   ( ( Second_d * ) p ) -> who() ;
}

运行结果:

在这里插入图片描述

在这里插入图片描述

注意
一个虚函数,在派生类层界面相同的重载函数都保持虚特性
虚函数必须是类的成员函数
不能将友元说明为虚函数,但虚函数可以是另一个类的友元
析构函数可以是虚函数,但构造函数不能是虚函数

虚函数的重载
虚析构函数

例题

成员函数调用析构函数(采用动态联编):

class Animal
{
 string name;
public:
 Animal(string a_name):name(a_name){}
 virtual void show(){}         //将来被派生类继承
 void show_name()
 {
  cout<< "The name is "<<name<<".<<endl;
 }
};
class Cat :public Animal
{
 string kind;
public:
 Cat(string a_name,string a_kind):Animal(a_name),kind(a_kind)
 {}
 void show();          //覆盖函数(同名同参数)
};
void Cat::show()
{
 show_name();
 cout<<" It's a "<<kind<<endl;
}
class Dog:public Animal
{
 string kind;
public:
 Dog(string a_name,string a_kind):Animal(a_name),kind(a_kind)
 {}
 void show();
};
void Dog::show()
{
 show_name();
 cout<<" It's a "<<kind<<endl;
}
class Tiger:public Cat
{
public:
 Tiger(string a_name,string a_kind):Cat(a_name,a_kind)
 {}
};
nt main()
{
 Animal *p;             //基类指针
 Cat cat("Tom","cat");
 Dog dog("Jerry","Dog");
 Tiger tiger("DuDu","Tiger");
 p=&cat;                //绑定猫对象
 p->show();
 p=&dog;  //绑定狗对象
 p->show();
 p=&tiger;  //绑定老虎对象
 p->show();
 return 0;
}

纯虚函数抽象类

在这里插入图片描述注意
纯虚函数在派生类中必须重写

虚函数与多态的应用

在这里插入图片描述
例题在这里插入图片描述

class Employee
{ 
 public:
       Employee(const int,const string );
       virtual ~Employee();   
       const string getName() const;
       const int getNumber() const;
       virtual double earnings() const=0;//雇员工资纯虚函数 
       virtual void print() const;
  protected:
       int number;  // 编号
       string name;  // 姓名
};
class Manager : public Employee
{ 
 public:
       Manager(const int , const string, double =0.0);
       ~Manager() { }
       void setMonthlySalary(double); //新增函数
       virtual double earnings() const;
       virtual void print() const;
  private:
      double monthlySalary ; 
};
class HourlyWorker : public Employee
{ 
 public:
       HourlyWorker(const long, const string, double=0.0, int =0 );
       ~HourlyWorker(){}
       void setWage(double);  
       void setHours(int);  
       virtual double earnings() const; 
       virtual void print() const; 
  private:
      double wage;
      double hours;
};
class PieceWorker : public Employee
{ 
 public:
       PieceWorker(const long , const string, double =0.0, int =0 );
       ~PieceWorker() { }
       void setWage ( double ) ; //完成件数 
       void setQuantity ( int ) ;  //价值
       virtual double earnings() const;
       virtual void print() const;
  private:
       double wagePerPiece; 
       int quantity;   
};

学习总结

通过对图书馆管理系统的一步步完善,渐渐把知识运用到了实际应用中,逐步消化慢慢掌握。
作业中用到的知识就是比着抄代码,以后应该多写代码,熟能生巧。

C++结课了,曾经因为C很喜欢编程,后来因为什么渐渐少了热爱。
加下来面临的是课程设计,是一个升华的任务,要重拾热爱,尽所能去完成任务!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值