继承学习总结

一、知识点

a.概念:在已有类的基础上创建新类的过程。一个B类继承A类或称从类A派生类B,类A称为基类(父类),类B称为派生类(子类)。【其中基类与派生类对应,父类与子类对应】

b.类继承关系的语法形式:

class 派生类名 : 基类名表

      {

            数据成员和成员函数声明

     };

基类名表构成:

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

访问控制表示派生类对基类的继承方式,使用关键字:

     public         公有继承

     private        私有继承

     protected    保护继承

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

      ●吸收基类成员(全部吸收(构造、析构除外),但不一定可见)

      ●改造基类成员

       ●添加派生类新成员

 1)吸收基类成员

         C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。

2)改造基类成员

       通过在派生类中定义同名成员(包括成员函数和数据成员)来屏蔽(隐藏)在派生类不起作用的部分基类成员

3)添加新成员

       仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。

d.常见继承关系

class Father

{

  int a,b;

public:

 // 成员函数

};

class Son:public Father

{

  int c;

public:

  // 成员函数

}; 

e . 公有继承
基类派生类
private成员 
protected成员protected成员
public成员public成员
 private成员
 protected成员
 public成员

:定义一个基类person(不定义构造函数)

姓名、性别、年龄(访问权限设置为私有)

定义公有的成员函数set_p()

定义公有的成员函数display_p(),显示person的信息

    再由基类派生出学生类(不定义构造函数,采用公有继承的方式)

n  增加学号、班级、专业和入学成绩

n  定义公有成员函数set_t()

n  定义成员函定义公有的成员函数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;

	}

	void show_t()	{

		show_p();

		cout<<zhuanye<<"  "<<t_class<<"  "<<score<<endl;

	}

};

f.重名成员

1)概念:派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽了基类的同名成员。

2)句法形式:
在派生类中使用基类的同名成员:
类名::成员

3)例:

class  base

  { 

public :

           int  a ,  b ;  

  } ;

class  derived : public  base

  { 

public :  

         int  b ,  c ; 

  } ;

void  f ()

{ 

derived  d ;

   d . a = 1 ;//直接调用基类的公有成员

   d . base :: b = 2 ;//使用重名成员

   d . b = 3 ;

   d . c = 4 ;

};

g.派生类中访问静态成员

Ø  基类定义的静态成员,将被所有派生类共享(基类和派生类共享基类中的静态成员)

Ø   根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质

Ø   派生类中访问静态成员,用以下形式显式说明:

                 类名 :: 成员

    或通过对象访问对象名 .成员

例:

#include<iostream> using namespace std ; class B { public: static void Add() { i++ ; } static int i; void out() { cout<<"static i="<<i<<endl; } }; int B::i=0; class D : private B { public: void f() { i=5; Add(); B::i++; B::Add(); } }; int main() { B x; D y; x.Add(); x.out(); y.f(); cout<<"static i="<<B::i<<endl; cout<<"static i="<<x.i<<endl; //cout<<"static i="<<y.i<<endl;
}

h.基类的初始化

1)在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据

2  派生类构造函数声明为:

派生类构造函数( 变元表) : 基类( 变元表) , 对象成员1( 变元表)

对象成员n (变元表 )

3)构造函数执行顺序:基类à对象成员à派生类

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






























     
       











  1. #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 ;
    
     }













9.派生类构造函数和析构函数的定义规则

        1基类的构造函数和析构函数不能被继承

2)如果基类没有定义构造函数或有无参的构造函数,派生类也可以不用定义构造函数

3)如果基类无无参的构造函数,派生类必须定义构造函数

4)如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造

5派生类是否定义析构函数与所属的基类无关

     派生类构造函数的定义:

     派生类的数据成员既包括基类的数据成员,也包括派生类新增数据成员。

     C++,派生类构造函数的一般格式为:

      派生类::派生类名(参数总表):基类名(参数表)

     {

            // 派生类新增成员的初始化语句

     }

     注意:这是基类有构造函数且含有参数时使用

派生类析构函数:

1)当派生类中不含对象成员时

●在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;

●在撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数。

2)当派生类中含有对象成员时

●在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;

●在撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数。

 例:

#include<iostream.h>

class base

{

public:

	base(){cout<<"constructing base class"<<endl;}

	~base(){cout<<"destructing base class"<<endl; }

};

class subs:public base

{

public:

	subs(){cout<<"constructing sub class"<<endl;}

	~subs(){cout<<"destructing sub class"<<endl;}

};

void main()

{

	subs s;

}

执行结果:

constructingbase class

constructingsub class

destructingsub class

destructingbase class

10.多继承

1)概念:一个类有多个直接基类的继承关系称为多继承

2)多继承语法声明:

        class  派生类名 : 访问控制  基类名1访问控制  基类名2 , 访问控制  基类名n

        {

             数据成员和成员函数声明

         }

3)类 C 可以根据访问控制同时继承类 A 和类 B 的成员,并添加自己的成员

        classA

        classB

         class Cpublic Apublic B

   4)多继承的派生类构造和访问

Ø 多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。

Ø 执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。

Ø  一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别

例:多继承的简单应用

class Base1

{ 

public:

      Base1(int x) { value = x ; }

      int getData() const { return value ; }

   protected:

      int value;

};

class Base2

{

 public:

      Base2(char c) { letter=c; }

      char getData() const { return letter;}

 protected:

      char letter;

};

class Derived : public Base1, public Base2

{   

friend ostream &operator<< ( ostream &, const Derived & ) ;

      public :

          Derived ( int, char, double ) ;

          double getReal() const ;

       private :

          double real ;

};

5)多继承的构造函数

句法形式:

派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),…,基类名n(参数表n)

    {

           // 派生类新增成员的初始化语句

     }

执行顺序:
    
●先执行所有基类的构造函数

●再执行对象成员的构造函数

●最后执行派生类的构造函数

【注】处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的基类顺序与派生类构造函数中所定义的成员初始化列表顺序没有关系

内嵌对象成员的构造函数执行顺序与对象在派生类中声明的顺序一致

6)多继承的析构函数:

析构函数名同样与类名相同,无返回值、无参数,而且其定义方式与基类中的析构函数的定义方式完全相同。

●功能是在派生类中对新增的有关成员进行必要的清理工作

●析构函数的执行顺序与多继承方式下构造函数的执行顺序完全相反,首先对派生类新增的数据成员进行清理,再对派生类对象成员进行清理,最后才对基类继承来的成员进行清理

11.赋值兼容规则:

1)概念:在程序中需要使用基类对象的任何地方,都可以用公有派生类的对象来替代。

2)其所指的替代包括以下几种情况:

        a 派生类的对象可以赋给基类对象

 b 派生类的对象可以初始化基类的引用

 c 派生类的对象的地址可以赋给基类类型的指针

 3)可行性:

通过公有继承,派生类得到了除了构造、析构函数以外的所有成员且这些成员的访问控制属性也和基类完全相同。这样,它便具备了基类的所有功能。

  4)例:下面声明两个类:

class Base

{

              … 

};

class Derived:public Base

{

… 

};

根据赋值兼容规则,以下几种情况是合法的:

1)可以用派生类对象给基类对象赋值。例如:

      Base b;

      Derived d;

      b=d;

         这样赋值的效果是,对象b中所有数据成员都将具有对象d中对应数据成员的值。

2)可以用派生类对象来初始化基类的引用。例如:

     Derived d;

     Base &br=d;

3)可以把派生类对象的地址赋值给指向基类的指针。例如:

   Derived d;

   Base *bptr=&d;

         这种形式的转换,是在实际应用程序中最常见到的。

4)可以把指向派生类对象的指针赋值给指向基类对象的指针。例如:

    Derived *dptr,obj; dptr=&obj;

    Base *bptr=dptr;

5)特点:
在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。

6)应注意的问题:

       1)声明为指向基类的指针可以指向它的公有派生类的对象,但不允许指向它的私有派生类的对象。例如:

       classB  {…}

       class Dprivate B  {…}

       B b1*pb1Dd1

       pb1=&b1;        //合法,基类B的对象b1B类的指针

       pb1=&d1;        //非法,不允许将基类指针指向它的私有派生类对象

2)允许将一个声明为指向基类的指针指向其公有派生类对象,但是不能将一个声明为指向派生类对象的指针指向其基类的一个对象。

3)  声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来直接访问派生类中从基类继承来的成员,而不能直接访问公有派生类的定义的成员

二,学习心得
使用继承可以帮我们更好的精简代码 继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行时间的效果。以后肯定要写越来越长的代码,繁重的代码会使人逻辑混乱,压迫感太强,而继承的使用不仅可以缩减代码,还可以更好理清逻辑性。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值