【C++面向对象程序设计】CH5 继承与派生

目录

前言

一、继承与派生的概念

二、派生类的声明方式

1.格式

2.【例】假定已经声明一个基类student,在它基础上通过单继承建立一个派生类student1。

三、派生类的构成

四、派生类成员的访问属性

前言

1.公有继承

(1)公有基类在派生类中的访问属性

(2)【例5.1】派生类访问公有继承的基类成员

(3)【例】公有继承举例

2.私有继承

(1)私有基类在派生类中的访问属性

(2)【例5.2】将例5.1中公有继承改为私有继承

3.保护成员和保护继承

(1)保护基类在派生类中的访问属性

(2)【例5.3】在派生类中访问保护成员

4.多级派生时的访问属性

(1)介绍

(2)【例5.4】多级派生类的访问属性。如果声明了以下的了类。

五、类型兼容规则

1.规则

2.类型兼容规则举例

3.基类与派生类的对应关系

4.多继承时派生类的声明

5.多继承举例

6.继承与派生的目的

六、派生类的构造函数和析构函数

前言——派生类的构造函数 

1.简单的派生类的构造函数

(1)介绍

(2)【例5.5】简单派生类的构造函数

(3)单一继承时的构造函数举例

2.有子对象的派生类的构造函数

(1)介绍

(2)【例】

3.多层派生时的构造函数

(1)介绍

(2)举例

4.派生类构造函数的特殊形式

5.派生类的析构函数

(1)介绍

(2)单一继承时构造函数、析构函数举例

七、多重继承

1.声明多重继承的方法

(1)介绍

(2)【例5.8】

2.多重继承派生类的构造函数

(1)派生类构造函数举例

(2)同名隐藏规则

(3)多继承同名隐藏举例

3.多重继承引起的二义性问题

(1)介绍

(2)二义性问题举例(一)

(3)二义性的解决方法

(4)二义性问题举例(二) 

(5)多重继承的同名问题


前言

        面向对象程序设计有四个主要特点:抽象、封装、继承和多态性。本文主要介绍有关继承的知识,在下一篇文章介绍多态性。

一、继承与派生的概念

        C++的继承机制实现软件可重用。有时两个类的内容基本相同或有一部分相同。例如已声明了类student:

class Student
{ 
	private :
	   int num;
	   string name;
	   char sex; 
    public:
	  	void display( )
	    {
			cout<<"num: "<<num<<endl;
	    	cout<<"name: "<<name<<endl;
	    	cout<<"sex: "<<sex<<endl;
		}
}; 

        如果另一个部门除了需要已有的数据外,还需要地址信息,你可以再声明另一个类:

class Student1
{
	private :
	    int num;
	    string name;
	    char sex;
	    char addr[20]; 
    public:
		void display()
	    { 
			cout<<"num: "<<num<<endl;
	        cout<<"name: "<<name<<endl;
	        cout<<"sex: "<<sex<<endl;
 	    	cout <<"address:"<< addr<<endl;
		}	
}; 

        可以看到新类中大部分成员是原来已有的。人们自然会想到能否利用原来声明的类student,加上新内容即可,以减少重复的工作。这就引出了C++的继承机制。

        所谓继承是在已存在的类A的基础上建立一个新类B。类A称为基类或父类,类B称为派生类或子类。子类从父类获得其已有的特性,这种现象称作类的继承。从另一个角度看从父类产生子类,称作类的派生

        一个基类可以派生出多个派生类,每个派生类又可以作为基类再派生新的派生类。一个派生类只从一个基类派生,称作单继承

        一个派生类也可从多个基类派生,也就是说一个派生类可以有两个或多个基类。一个派生类有两个或多个基类的称为多重继承。基类和派生类的关系可以表述为:派生类是基类的扩充,而基类是派生类的抽象

二、派生类的声明方式

1.格式

        使用派生类要先声明,声明的格式为:

class  派生类名: [继承方式] 基类名
{      
    派生类新增成员声明    
};

        继承方式包括:public、private、protected。如果省略,默认为private。

2.【例】假定已经声明一个基类student,在它基础上通过单继承建立一个派生类student1。

class Student1: public Student
{  
	private:
	    int age;
	    string addr;
    public:
	    void display_1()
	    {  
			cout <<"age: "<<age<<endl;
	    	cout <<"address: "<<addr<<endl;
		}
};

三、派生类的构成

        派生类中的成员包括从基类继承过来的成员和自己增加的成员。继承基类成员体现了同一基类的派生类都具有的共性,而新增加的成员体现了派生类的个性

  • 从基类接受成员:派生类将基类除构造函数和析构函数外的所有成员接收过来
  • 调整从基类接受的成员:一方面可以通过继承方式改变基类成员在派生类中的访问属性,另一方面可以在派生类中声明一个与基类成员同名的成员屏蔽基类的同名成员,注意如是成员函数不仅要函数名相同,而且函数的参数也要相同,屏蔽的含义是用新成员取代旧成员
  • 在声明派生类时增加成员:它体现了派生类对基类功能的补充
  • 在声明派生类时,还要自己定义派生类的构造函数

四、派生类成员的访问属性

前言

        派生类中包含了基类成员和派生类成员,就产生了这两部分成员的关系和访问属性的问题。这个关系由基类成员的访问属性和派生类的继承方式组合决定。

1.公有继承

(1)公有基类在派生类中的访问属性

        当派生类的继承方式为public(公有)属性时,在派生类中,基类的公有成员和保护成员在派生类中的访问属性没有变化,即分别作为派生类的公有成员和保护成员,派生类的成员可以直接访问它们。但是,派生类的成员无法直接访问基类的私有成员。保护私有成员是一条重要的原则。

(2)【例5.1】派生类访问公有继承的基类成员

class Student1: public Student
{
	private:
	    int age;
	    string addr; 
	public:
	   void get_value_1()
			{
				cin>>age>>addr;
			}
	   void display_1()
	    {  
			//cout<<"num: "<<num<<endl;      //  错误
	    	//cout<<"name: "<<name<<endl;   //  错误
	    	//cout<<"sex: "<<sex<<endl;          //  错误
	    	cout<<"age: "<<age<<endl;               //  正确
	    	cout<<"address: "<<addr<<endl;		//  正确
		}      
};

【解释】

        由于基类的私有成员对派生类说是不能访问的,所以派生类的成员函数display_1不能直接访问基类的私有成员,只能通过基类的公有成员函数访问基类的私有成员。

        因为是公有继承,基类的公有成员在派生类中仍是公有,所以派生类的对象可以通过基类的公有成员函数访问基类的私有数据成员,也可以在派生类的成员函数中调用基类的公有成员函数,访问基类的私有数据成员。

方法一:

int main()
{	
	Student1 stud1;
	…  … 
	stud1.display();
	stud1.display_1();
	return 0;
} 

方法二:

void display_1()
{ 	
	display();    //派生类成员调用基类公有成员
	cout<<"age: "<<age<<endl;              //  正确
	cout<<"address: "<<addr<<endl; 	//  正确
}   
int main()
{
	Student1 stud1;
	stud1.get_value();
	stud1.get_value_1();
	stud1.display_1();
	return 0;
} 

(3)【例】公有继承举例

class Point 
{	//基类Point类的声明
	public:	//公有函数成员
		void InitP(float xx = 0, float yy = 0) 
		{
			X = xx;
			Y = yy;
		}
		void Move(float xOff, float yOff) 
		{
			X += xOff;
			Y += yOff;
		}
		float GetX() 
		{
			return X;
		}
		float GetY() 
		{
			return Y;
		}
	private:	//私有数据成员
		float X, Y;
};

class Rectangle: public Point 
{ //派生类声明
	public:	//新增公有函数成员
		void InitR(float x, float y, float w, float h) 
		{
			InitP(x, y);    //调用基类公有成员函数
			W = w;
			H = h;
		}
		float GetH() 
		{
			return H;
		}
		float GetW() 
		{
			return W;
		}
	private:	//新增私有数据成员
		float W, H;
};
#include <iostream>
#include <cmath>
using namespace std;

int main() 
{
	Rectangle rect;
	rect.InitR(2, 3, 20, 10);
	//通过派生类对象访问基类公有成员
	rect.Move(3, 2);
	cout << rect.GetX() << ','
	     << rect.GetY() << ','
	     << rect.GetH() << ','
	     << rect.GetW() << endl;
	return 0;
}

2.私有继承

(1)私有基类在派生类中的访问属性

        在派生类中,基类的公有成员和保护成员作为派生类的私有成员,派生类的成员可以直接访问他们,而派生类的成员无法直接访问基类的私有成员。

        在派生类的外部,派生类的对象无法访问基类的全部对象。

        私有继承之后,全部基类成员在派生类中都成为了私有成员或不可访问的成员,无法进一步派生。私有成员一般很少使用。

(2)【例5.2】将例5.1中公有继承改为私有继承

class Student 
{
	private :
		int num;
		string name;
		char sex;
	public:
		void display( ) 
		{
			cout << "num: " << num << endl;
			cout << "name: " << name << endl;
			cout << "sex: " << sex << endl;
		}
};

class Student1: private Student 
{
	private:
		int age;
		string addr;
	public:
		void display_1() 
		{
			display();
			cout << "age: " << age << endl;       //  正确
			cout << "address: " << addr << endl;	//  正确
		}
};

int main() 
{
	Student1 stud1;
	stud1.display_1();
	return 0;
}

3.保护成员和保护继承

(1)保护基类在派生类中的访问属性

        当派生类的继承方式为protected继承属性时,在派生类中,基类的公有成员和保护成员均作为派生类的保护成员,派生类的成员可以直接访问他们,而派生类的成员无法访问基类的私有成员。

        在派生类的外部,派生类的对象无法访问基类的全部成员。

        如果基类只进行了一次派生,则保护继承和私有继承的功能完全相同,但保护继承可以进一步派生,而私有继承则不可以,两者具有实质性差别。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值