C++面向对象程序设计 - 继承与派生

news2024/11/20 0:06:23

        面向对象技术强调软件的可重用性(software reusability),C++语言提供了类的继承机制,解决了软件重用问题。

        C++中所谓“继承”就是在一个已存在的类的基础上建立一个新类,从已有的类那里获得已有特性,叫做类的继承。从另一角度说,从已有的类(父类)产生一个新的子类,称为类的派生。

        一个派生类只从一个基类派生,这称为单继承;一个派生类有两个或多个基类,称为多继承。派生类是基类的具体化,而基类则是派生类的抽象。

一、派生类的声明方式

        声明派生类的一般形式为:

class 派生类: [继承方式] 基类

{

        派生类新增加的成员

};

        继承方式包括:public(公用的)、private(私有的)、protected(受保护的),继承方式是可选的,如果不写此项,则默认为private(私有的)。

        示例代码如下:

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	private:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "无名氏";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
};
// 派生类 - 学生
class Student: public Person{
	private:
		string school;
	public:
		void display(){}
};
int main(){
	return 0;
}

二、派生类的构成

        派生类中的成员包括从基类继承过来的成员和自己增加的成员两大部分,从基类继承的成员体现了派生类从基类继承而获得的共性,而新增加的成员体现了派生类的个性。

构造一个派生类包括三部分工作:

  1. 从基类接收成员:派生类把基类全部的成员(不包括构造函数和析构函数)接收过来,必须全部接收,不能舍弃一部分。
  2. 调整从基类接收的成员:接收基类成员是不可选择的,但是可以对这些成员作些调整。例如可以改变基类成员在派生类中的访问属性,这可以通过指定继承方式来实现。
  3. 在声明派生类时增加的成员。

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

        派生类中包含基类成员和派生类新增的成员,对基类成员和派生类新增的成员是按不同的原则处理的,在访问属性时,需要考虑以下几种情况:

  1. 基类的成员函数访问基类成员。
  2. 派生类的成员函数访问派生类自己增加的成员。
  3. 基类成员函数访问派生类的成员。
  4. 派生类的成员函数访问基类的成员。
  5. 在派生类外访问派生类的成员。
  6. 在派生类外访问类的成员。

        在派生类中,对基类的继承方式可以有public、private、protected三种,不同的继承方式决定了基类成员在派生类中的访问属性。

  1. 公用继承(public inheritance):基类的公用或保护成员在派生类中保持原有访问属性,其私有成员扔为基类私有。
  2. 私有继承(private inheritance):基类的公用成员和保护成员在派生类中成了私有成员,其私有成员仍为基类私有。
  3. 受保护的继承(protected inheritance):基类的公用成员和保存成员在派生类中成了保护成员,其私有成员仍为其类私有。

3.1 公用继承

        在定义一个派生类时将基类的继承方式指定为public,称为公用继承,用公用继承方式建立的派生类称为公用派生类(public derived class),其基类称为公用基类(public base class)。

        公用基类的成员在派生类的访问属性如下表:

公用基类的成员在公用派生类中的访问属性
私有成员不可访问
公用成员公用
保护成员保护

        如下例中,派生类中是不能访问基类中的私有成员,代码如下:

// 基类 - 人类
class Person{
	private:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "无名氏";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
		void display(){
			// 正确,基类中可以访问基类中的私有成员
			cout <<name <<"," <<age <<"," <<gender <<endl;
		}
};
// 派生类 - 学生
class Student: public Person{
	private:
		string school;
	public:
		void display(){
			// 错误,派生类中不能访问基类中的私有成员
			cout <<name <<"," <<age <<"," <<gender <<"," <<school <<endl;
		}
};

        如上代码,派生类Student调用基类Person中的私有成员,会报错【[Error] 'std::string Person::name' is private within this context】- 在这个上下文中,'std:string Person::name'是私有的。同理,age,gender都会报同类错误。

3.2.私有继承

        在声明一个派生类时将基类的继承方式指定为private,称为私有继承,用私有继承方式建立的派生类称为私有派生类(private derived class),其基类称为私有基类(private base class)。

        私有基类在派生类中的访问属性如下表:

私有基类中的成员在私有派生类中的访问属性

私有成员

不可访问
公用成员私有
保护成员私有

        如下列,在基类中为公用成员,在派生类继承时被指定为私有,则基类中公用成员在派生类中变有私有,外部不可调用 ,代码如下:

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	private:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "无名氏";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
		// 获取名称
		string getName(){
			return name;
		}
};
// 派生类 - 学生
class Student: private Person{
	private:
		string school;
	public:
		void display(){
			// 错误,派生类中不能访问基类中的私有成员
			cout  <<school <<endl;
		}
};
int main(){
	Student s;
	string name = s.getName();		// 错误,当基类被指定为私有时,基类中公用成员在派生类中变为私有,外部不可调用
	cout <<name;
	s.display();		//正确,派生类中新增公用成员
	return 0;
}

        如上代码,执行s.getName()则会报错【[Error] 'std::string Person::getName()' is inaccessible within this context】- 'std::string Person::getName()'在此上下文中不可访问。

3.3 受保护的继承

        在定义一个派生类时将基类的继承方式指定为protected时,称为保护继承。用保护继承方式建立的派生类称为保护派生类(protected derived class),其基类称为保护的基类(protected base class)。

        保护继承的特点是,保护基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为基类私有。基类成员在派生类中的访问属性如下表:

基类中的成员在公用派生类中的访问属性在私有派生类中的访问属性在保护派生类中的访问属性
私有成员不可访问不可访问不可访问
公用成员公用私有保护
保护成员保护私有保护

        保护基类的所有成员在派生类中都被保护起来,类外不能访问,其公用成员和保护成员可以被其派生类的成员函数访问。

        示例代码如下 :

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	protected:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
		// 获取名称
		string getName(){
			return name;
		}
	public:
		Person(){
			name = "无名氏";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
};
// 派生类 - 学生
class Student: protected Person{
	private:
		string school;
	public:
		void display(){
			string str_name = getName();	// 合法,派生类中可以调用基类中的保护成员
			cout <<"str name:" <<str_name <<endl;
			// 错误,派生类中不能访问基类中的私有成员
			cout  <<name <<"," <<age <<"," <<gender <<"," <<school <<endl;
		}
};
int main(){
	Student s;
	string name = s.getName();		// 错误,当基类被指定为保护类时,基类中保护成员在派生类中可被调用,外部不可调用
	cout <<name;
	s.display();		//正确,派生类中新增公用成员
	return 0;
}

        如上代码,当s.getName()保护成员是不能被外部调用的,否则会报错【[Error] 'std::string Person::getName()' is protected within this context】- 'std::string Person::getName()'在此上下文中受保护。

3.4 多级派生时的访问属性

        目前了解了一级派生的情况,但实际上,经常会有多级派生的情况。在多级派生的情况下,各成员的访问属性仍按以上原则确定。

        示例代码:

#include <iostream>
using namespace std;
class A{
	public:
		void displayPublic(){
			cout <<"A::displayPublic()" <<endl;
		}
	protected:
		void displayProtected(){
			cout <<"A::displayProtected()" <<endl;
		}
	private:
		void displayPrivate(){
			cout <<"A::displayPrivate()" <<endl;
		}
};
class B: public A{
	public:
		void displayBPublic(){
			cout <<"B::displayBPublic()" <<endl;
			displayPublic();	
			displayProtected();
//			displayPrivate();		// 错误,基类私有成员在派生类中无法访问
			/**
			 否则会报错:[Error] 'void A::displayPrivate()' is private within this context
			*/
		}
};
class C: public B{
	public:
		void displayCPublic(){
			cout <<"C::displayCPublic()" <<endl;
			displayPublic();	
			displayProtected();
//			displayPrivate();		// 错误,基类私有成员在派生类中无法访问
		}
};
int main(){
	B b;
	b.displayPublic();
//	b.displayProtected();		// 错误,保护成员在派生类外无法调用
//	b.displayPrivate();			// 错误,私有成员在派生类外无法调用 
	b.displayBPublic();
	
	C c;
	c.displayPublic();
//	c.displayProtected();		// 错误,保护成员在派生类外无法调用
//	c.displayPrivate();			// 错误,私有成员在派生类外无法调用 
	c.displayBPublic();
	c.displayCPublic();
	return 0;
}

        以上示例可以看出,保护成员在派生类外是无法调用的,私有成员在派生类中也无法调用。运行结果如下图:

        示例分析:

  1. 类A中有个成员函数,分别具有public、protected、private访问属性。
  2. 类B公有继承类A,因此它可以访问类A的公有和保护成员,但不能访问私有成员。
  3. 类C公有继承类B,因此它可以访问类B的公有成员和保护成员,以及类B从类A中继承过来的公用和保护成员,但不能访问类B或类A的私有成员。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1624022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络协议深度解析:SSL、 TLS、HTTP和 DNS(C/C++代码实现)

在数字化时代&#xff0c;网络协议构成了互联网通信的基石。SSL、TLS、HTTP和DNS是其中最关键的几种&#xff0c;它们确保了我们的数据安全传输、网页的正确显示以及域名的正常解析。 要理解这些协议&#xff0c;首先需要了解网络分层模型。SSL和TLS位于传输层之上&#xff0c…

说说2024年暑期三下乡社会实践工作新闻投稿经验

作为一名在校大学生,我有幸自去年起参与学院组织的暑期大学生三下乡社会实践团活动。这项活动不仅是我们深入基层、服务社会的重要平台,也是展现当代大学生风采、传递青春正能量的有效途径。然而,如何将这些生动鲜活的实践故事、感人至深的瞬间传播出去,让更多人了解并受到启发…

在PostgreSQL中如何创建和使用自定义函数,包括内置语言(如PL/pgSQL)和外部语言(如Python、C等)?

文章目录 一、使用内置语言 PL/pgSQL 创建自定义函数示例代码使用方法 二、使用外部语言 Python 创建自定义函数安装 PL/Python 扩展示例代码使用方法 三、使用外部语言 C 创建自定义函数编写 C 代码编译为共享库在 PostgreSQL 中注册函数注意事项 总结 PostgreSQL 是一个强大的…

前端H5动态背景登录页面(下)

最近正好有点儿时间&#xff0c;把之前没整理完的前端动态背景登录页面给整理一下&#xff01;这是之前的连接前端H5动态背景登录页面&#xff08;上&#xff09;&#xff0c;这主要是两个登陆页面&#xff0c;一个彩色气泡&#xff0c;一个动态云朵&#xff0c;感兴趣的可以点…

08 内核开发-避免冲突和死锁-mutex

08 内核开发-避免冲突和死锁-mutex 课程简介&#xff1a; Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础&#xff0c;让他们能够理解和参与到Linux内核的开发过程中。 …

U盘无法正常格式化?教你一个强力的办法

前言 电脑格式化U盘或者移动硬盘的操作&#xff0c;相信各位小伙伴都是有一定经历的。 如果设备正常&#xff0c;那么进入到【此电脑】&#xff0c;在对应的分区点击【鼠标右键】-【格式化】就可以把对应的存储设备恢复到初始状态。 但凡事都会有例外&#xff0c;比如在格式化…

实验 | RT-Thread:L1

1 线程间同步 同步是指按预定的先后次序进行运行&#xff0c;线程同步是指多个线程通过特定的机制&#xff08;如互斥量&#xff0c;事件对象&#xff0c;临界区&#xff09;来控制线程之间的执行顺序&#xff0c;也可以说是在线程之间通过同步建立起执行顺序的关系&#xff0…

海外短剧:跨文化的新浪潮与看剧系统的搭建,海外短剧系统搭建开发定制

在全球化的大潮下&#xff0c;海外短剧作为一种新兴的文化交流方式&#xff0c;正逐渐受到越来越多人的喜爱。这种融合了各地文化元素、叙事手法新颖独特的短剧形式&#xff0c;不仅丰富了观众的视觉体验&#xff0c;也为影视媒体和想拓展海外市场的企业带来了无限商机。 一、…

【深度学习-第5篇】使用Python快速实现CNN分类(模式识别)任务,含一维、二维、三维数据演示案例(使用pytorch框架)

在之前的文章中介绍了CNN的图解入门&#xff0c;CNN的MATLAB分类实现&#xff0c;CNN的MATLAB回归实现。 卷积神经网络(Convolutional Neural Networ&#xff0c;简称CNN)是一种广泛应用于图像识别领域的深度学习算法。它通过模拟人类视觉系统的层次结构&#xff0c;可以自动提…

Docker NetWork (网络)

Docker 为什么需要网络管理 容器的网络默认与宿主机及其他容器都是相互隔离的&#xff0c;但同时我们也要考虑下面的一些问题&#xff0c; 比如 多个容器之间是如何通信的容器和宿主机是如何通信的容器和外界主机是如何通信的容器中要运行一些网络应用(如 nginx、web 应用、数…

HarmonyOS hsp制作与引用

1. HarmonyOS hsp制作与引用 1.1 介绍 HSP动态共享包&#xff08;模块&#xff09;,应用内HSP指的是专门为某一应用开发的HSP&#xff0c;只能被该应用内部其他HAP/HSP使用&#xff0c;用于应用内部代码、资源的共享。应用内HSP跟随其宿主应用的APP包一起发布&#xff0c;与该…

「deepin生态共建小组」正式启动招募!三大生态共建项目,速来 !

基于社区开源精神&#xff0c;为提高大家对deepin生态建设的参与感&#xff0c;应用商店将正式开放众多软件给广大开源爱好者进行维护。参与小组工作可获得多项专属小组福利&#xff0c;工作项目分为玲珑格式迁移、wine应用打包、deb原生应用维护。 招募条件 1&#xff09;不限…

【C/C++笔试练习】OSI分层模型、源端口和目的端口、网段地址、SNMP、状态码、tcp报文、域名解析、HTTP协议、计算机网络、美国节日、分解因数

文章目录 C/C笔试练习选择部分&#xff08;1&#xff09;OSI分层模型&#xff08;2&#xff09;源端口和目的端口&#xff08;3&#xff09;网段地址&#xff08;4&#xff09;SNMP&#xff08;5&#xff09;状态码&#xff08;6&#xff09;tcp报文&#xff08;7&#xff09;域…

使用python setup.py报错:Upload failed (403) / Upload failed (400)

当前报错的环境 Python 3.9.19twine1.15.0 本地~/.pypirc已正确配置了用户名和密码&#xff0c;用在pypi.org注册&#xff1a; [pypi]username skylerhupassword ${password}执行 python setup.py sdist upload -r pypi 打包上传到仓库报错。 在不久之前同样的环境&#…

C语言扫雷游戏完整实现(上)

文章目录 前言一、新建好头文件和源文件二、实现游戏菜单选择功能三、定义游戏函数四、初始化棋盘五、 打印棋盘函数六、布置雷函数七、玩家排雷菜单八、标记功能的菜单九、标记功能菜单的实现总结 前言 C语言从新建文件到游戏菜单&#xff0c;游戏函数&#xff0c;初始化棋盘…

网工交换基础——生成树协议(01)

一、生成树的技术概述 1、技术背景 二层交换机网络的冗余性导致出现二层环路&#xff1a; 人为因素导致的二层环路问题&#xff1a; 二层环路带来的网络问题&#xff1a; 生成树协议的概念&#xff1a; STP(Spanning Tree Protocol)是生成树协议的英文缩写。该协议可应用于在网…

如何分析和优化慢sql语句

前言 sql查询速度比较慢容易成为性能瓶颈,这时我们可以优化我们的sql语句或数据库表 一般sql语句执行很慢的种类分为: 1.聚合查询 2.多表查询 3.表数据量过大查询 4.深度分页查询 这四种的前三种都可以通过优化sql语句来优化sql查询速度 正文 聚合查询 我们可以通过尝…

机器人视觉教学实训平台

一&#xff1a;功能概述 1.1、功能简介 机器人视觉教学实训平台基于睿尔曼机器人与海康机器视觉产品&#xff0c;面向机器人视觉系统应用而开发设计&#xff0c;产品涵盖机器人系统、工业视觉系统、自动化控制系统、计算机编程系统&#xff0c;可以在一台设备上进行多种与机器…

C++初阶学习第三弹——类与对象(上)——初始类与对象

前言&#xff1a; 在前面&#xff0c;我们已经初步学习了C的一些基本语法&#xff0c;比如内敛函数、函数重载、缺省参数、引用等等&#xff0c;接下来我们就将正式步入C的神圣殿堂&#xff0c;首先&#xff0c;先给你找个对象 目录 一、类与对象是什么&#xff1f; 二、类的各…

Git 工作原理

Git 工作原理 | CoderMast编程桅杆https://www.codermast.com/dev-tools/git/git-workspace-index-repo.html Workspace&#xff1a;工作区Index / Stage&#xff1a;暂存区Repository&#xff1a;仓库区&#xff08;或本地仓库&#xff09;Remote&#xff1a;远程仓库 Git 一…