C# 继承

news2024/11/25 22:45:43

C# 继承

  • 继承的类型
  • 实现继承
  • 虚方法
  • 隐藏方法
  • 调用函数的基类版本
  • 抽象类和抽象函数
  • 密封类和密封方法
  • 派生类的构造函数
  • 修饰符
    • 访问修饰符
    • 其他修饰符
  • 接口

继承的类型

  • 实现继承
    表示一个类型派生于一个基类型,拥有该基类型的所有成员字段和函数。在实现继承中,派生类型的每个函数采用基类型的实现代码,除非在派生类型的定义中指定重写该函数的实现代码。
  • 接口继承
    表示一个类型只继承了函数的签名,没有继承任何实现代码。在需要指定该类型具
    有某些可用的特性时,最好使用这种类型的继承。
  • 多重继承
    一些语言如 C++支持所谓的"多重继承",即一个类派生于多个类。
  • 结构和类
    结构(值类型)和类(引用类型)。使用结构的一个限制是结构不支持继承,但每个结构都自动派生于 System.ValueType。实际上还应更仔细一些:不能建立结构的类型层次,但结构可以实现接口。换言之,结构并不支持实现继承,但支持接口继承。事实上,定义结构和类可以总结为:
    • 结构总是派生于 System.ValueType,它们还可以派生于任意多个接口。
    • 类总是派生于用户选择的另一个类,它们还可以派生于任意多个接口。

实现继承

声明一个类派生于另一个类,可以使用下面的语法:

class MyClass : MyBaseClass
{
	// 函数和数据成员
}

声明一个类继承其他类和接口

class MyClass : MyBaseClass, IMyInterface1, IMyInterface2
{
	// 函数和数据成员
}

声明一个结构继承其他接口

struct MyStruct : IMyInterface1, IMyInterface2
{
	// ...
}

虚方法

把一个基类函数声明为 virtual,该函数就可以在派生类中重写了:

class MyBaseClass
{
	public virtual string VirtualMethod()
	{
		return "base method:VirtualMethod";
	}
}

把一个属性声明为virtual,对于虚属性或重写属性,语法与非虚属性是相同的,但要在定义中
加上关键字 virtual,其语法如下所示

public virtual string ForeName
{
	private string foreName;
	get { return foreName;}
	set { foreName = value;}
}

C#中虚函数的概念与标准 OOP 概念相同:可以在派生类中重写虚函数。在调用方法时,会调用对象类型的合适方法。在 C#中,函数在默认情况下不是虚拟的,但(除了构造函数以外)可以显式地声明为 virtual。

class MyClass : MyBaseClass
{
	public override string VirtualMethod()
	{
		return "override method:VirtualMethod";
	}
}

隐藏方法

如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为 virtual 和 override,派生类方法就会隐藏基类方法。在大多数情况下,是要重写方法,而不是隐藏方法,因为隐藏方法会存在为给定类的实例调用错误方法的危险。
假定有人编写了类 HisBaseClass:

class HisBaseClass
{
}

某一时刻编写了一个派生类,给 HisBaseClass 添加某个功能,特别是要添加一个目前基类中没有的方法 MyGroovyMethod():

class MyDerivedClass : HisBaseClass
{
	public int MyGroovyMethod()
	{
		return 0;
	}
}

一年后,基类的编写者决定扩展基类的功能。为了保持一致,他也添加了一个名为MyGroovyMethod()的方法,该方法的名称和签名与前面添加的方法相同,但并不完成相同的工作。在使用基类的新方法编译代码时,程序在应该调用哪个方法上就会有潜在的冲突。这在 C#中完全合法,但因为我们的 MyGroovyMethod()与基类的 MyGroovyMethod()不相关,运行这段代码的结果就可能不是我们希望的结果。C#已经为此设计了一种方式,可以很好地处理这种情况。
首先,系统会发出警告。在 C#中,应使用 new 关键字声明我们要隐藏一个方法,如下所示:

class MyDerivedClass: HisBaseClass
{
	public new int MyGroovyMethod()
	{
		return 0;
	}
}

调用函数的基类版本

C#有一种特殊的语法用于从派生类中调用方法的基类版本:base.< MethodName >()。

class CustomerAccount
{
	public virtual decimal CalculatePrice()
	{
		return 0.0M;
	}
}

class GoldAccount : CustomerAccount
{
	public override decimal CalculatePrice()
	{
		return base.CalculatePrice() * 0.8M;
	}
}

抽象类和抽象函数

C#允许把类和函数声明为 abstract,抽象类不能实例化,而抽象函数没有执行代码,必须在非抽
象的派生类中重写。显然,抽象函数也是虚拟的(但也不需要提供 virtual 关键字,实际上,如果提供了该关键字,就会产生一个语法错误)。如果类包含抽象函数,该类将也是抽象的,也必须声明为抽象的:

abstract class Building	// 抽象类
{
	private bool damaged = false; // 成员字段初始值
	public abstract decimal CalculateHeatingCost(); // 抽象方法
}

密封类和密封方法

C#允许把类和方法声明为 sealed。对于类来说,这表示不能继承该类;对于方法来说,这表示不能重写该方法。sealed 与java中的final相同。

sealed class FinalClass
{
	//....
}
FinalClass 类不能被其他类继承

class MyClass
{
	public sealed void FinalMethod()
	{
	}
}
FinalMethod不能再MyClass的派生类中重写。

派生类的构造函数

  1. 在层次结构中添加无参数的构造函数
public abstract class GenericCustomer
{
	private string name;
	public GenericCustomer()
	:base() // 使用base表示这是基类构造函数
	{
		name = "< no name >";
	}
	
}
  1. 在层次结构中添加带参数的构造函数
abstract class GenericCutomer
{
	private string name;
	public GenericCutomer(string name)
	{
		this.name = name;
	}
}
class Nevermore60Customer : GenericCutomer
{
	public Nevermore60Customer(string name, string referrerName)
	:base(name)
	{
		this.referrerName = referrerName;
	}
	private string referrerName;
	private uint highCostMinutesUesd;
}

修饰符

访问修饰符

在这里插入图片描述

其他修饰符

在这里插入图片描述

接口

接口有interface声明

public interface IDisposable
{
	void Dispose();
}

类派生接口

class SomeClass:IDisposable
{
	public void Dispose()
	{
		// 实现接口方法
	}
}

接口的定义

namespace Wrox.ProCSharp
{
	public interface IBankAccount
	{
		void PlayIn(decimal amount);
		bool Withdraw(decimal amount);
		decimal Balance
		{
			get;
		}
	}

}

接口的继承

namespace Wrox.ProCSharp.VenusBank
{
	public class SaverAccount : IBankAccount
	{
		private decimal balance;
		public void PayIn(decimal amount)
		{
			balance += amount;	
		}
		public bool Withdraw(decimal amount)
		{
			if (balance >= amount)
			{
				balance -= amount;
				return true;
			}
			Console.WriteLine("error.");
			return false;
		}
		public decimal Balance
		{
			get 
			{
				return balance;	
			}
		}
		public override string ToString()
		{
			return String.Format("Vens Bank Saver: Balance = {0,6:C}", balance);
		}
	}

}

不同类实现相同的接口

namespace Wrox.ProCSharp.JupiterBank 
{
	public class GoldAccount:IBankAccount
	{
		// ...
	}
}

测试代码

using System;
using Wrox.ProCSharp;
using Wrox.ProCSharp.VenusBank;
using Wrox.ProCSharp.JupiterBank;

namespace Wrox.ProCSharp
{
	class MainEntryPoint
	{
		static void Main(string[] args)
		{
			IBankAccount venusAccount = new SaverAccount();
			IBankAccount jupiterAccount = new GoldAccount();
			venusAccount.PayIn(200);
			venusAccount.Withdraw(100);
			Console.WriteLine(venusAccount.ToString());
			jupiterAccount.PayIn(500);
			jupiterAccount.Withdraw(600);
			jupiterAccount.Withdraw(100);
			Console.WriteLine(jupiterAccount.ToString());
		}
	}
}

接口数组

IBankAccount[] accounts = new IBankAccount[2];

accounts[0] = new SaverAccount();
accounts[1] = new GoldAccount();

派生接口
接口可以彼此继承,其方式与类的继承相同。

namespace Wrox.ProCSharp
{
	public interface ITransferBankAccount: IBankAccount
	{
		bool TransferTo(IBankAccount desination, decimal amount);
	}
}

派生接口类

public class CurrentAccount : ITransferBankAccount
{
	private decimal balance;
	public void PayIn(decimal amount)
	{
		balance += amount;
	}
	public bool Withdraw(decimal amount)
	{
		if (balance >= amount)
		{
			balance -= amount;
			return true;
		}
		Console.WriteLine("Withdrawal failed.");
		return false;
	}
	public decimal Balance
	{
		get { return balance;}
	}
	public bool TransferTo(IBankAccount destination, decimal amount)
	{
		bool result;
		if ((result = Withdraw(amount)) == true)
		{
			destination.PayIn(amount);
			return result;
		}
	}
	
	public override string ToString()
	{
		return String.Format("Jupiter Bank Current Account:Balance = {0, 6:C}", balance);
	}
}

// 验证代码

static void Main()
{
	IBankAccount venusAccount = new SaverAccount();
	ITransferBankAccount jupiterAccount = new CurrentAccount();
	venusAccount.PayIn(200);
	jupiterAccount.PayIn(500);
	jupiterAccount.TransferTo(venusAccount, 100);
	Console.WriteLine(venusAccount.ToString());
	Console.WriteLine(jupiterAccount.ToString());
}

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

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

相关文章

【接口测试学习】白盒测试 接口测试 自动化测试

一、什么是白盒测试 白盒测试是一种测试策略&#xff0c;这种策略允许我们检查程序的内部结构&#xff0c;对程序的逻辑结构进行检查&#xff0c;从中获取测试数据。白盒测试的对象基本是源程序&#xff0c;所以它又称为结构测试或逻辑驱动测试&#xff0c;白盒测试方法一般分为…

无代码赋能数字化,云表搭桥铺路链接“数据孤岛”

什么是信息孤岛 企业数字化转型过程中&#xff0c;信息孤岛是一个突出的问题。这种情况发生的原因是&#xff0c;企业内部使用了多种应用软件&#xff0c;时间一长&#xff0c;员工在不同的系统中积累了大量的企业数据资产。然而&#xff0c;由于这些系统之间的数据无法互通&am…

Cruise 的界面和模型文件路径介绍

文章目录 打开 Cruise自带模型所在路径自带模型分类Cruise 中的模型路径解析打开用户手册建模界面介绍打开模型 打开 Cruise 最新的几个 Cruise 软件都是集成到一个平台上的&#xff0c;名为 AVL Advanced Simulation Desktop。 自带模型所在路径 User 选项卡下的模型&#x…

canvas手写签名组件

效果图&#x1f447; 代码不多直接粘在这里 <template><div class"border"><canvasref"canvas"width"800"height"500"class"border-success"tabindex"0"mousedown"onMouseDown"/>&…

云可观测性安全平台——掌动智能

云可观测性安全平台是一个跨架构、跨平台的可观测性方案&#xff0c;实现对云环境下的细粒度数据可视化&#xff0c;满足安全部门对云内部安全领域的多场景诉求&#xff0c;包括敏感数据动态监管、云网攻击回溯分析、攻击横移风险监控、云异常流量分析。本文将介绍掌动智能云可…

【RabbitMQ实战】01 3分钟在Linux上安装RabbitMQ

本节采用docker安装RabbitMQ。采用的是bitnami的镜像。Bitnami是一个提供各种流行应用的Docker镜像和软件包的公司。采用docker的方式3分钟就可以把我们想安装的程序运行起来&#xff0c;不得不说真的很方便啊&#xff0c;好了&#xff0c;开搞。使用前提&#xff1a;Linux虚拟…

验证NIO的非阻塞模型

我们知道传统BIO模型在等待客户端连接时是阻塞的&#xff0c;读取数据时如果没有数据&#xff0c;也是阻塞的&#xff0c;而NIO则可以配置成非阻塞&#xff0c;废话不多说&#xff0c;直接看代码&#xff1a; import java.net.InetSocketAddress; import java.nio.ByteBuffer;…

OWASP Top 10漏洞解析(2)- A2:Cryptographic Failures 加密机制失效

作者&#xff1a;gentle_zhou 原文链接&#xff1a;OWASP Top 10漏洞解析&#xff08;2&#xff09;- A2:Cryptographic Failures 加密机制失效-云社区-华为云 Web应用程序安全一直是一个重要的话题&#xff0c;它不但关系到网络用户的隐私&#xff0c;财产&#xff0c;而且关…

服务器补丁管理软件

随着漏洞的不断上升&#xff0c;服务器修补是增强企业网络安全的典型特征。作为业务关键型机器&#xff0c;计划服务器维护的停机时间无疑是一件麻烦事。但是&#xff0c;借助高效的服务器补丁管理软件&#xff08;如 Patch Manager Plus&#xff09;&#xff0c;管理员可以利用…

港联证券:市场有望从2024年起进入大众化折叠屏手机时代

根据Counterpoint Research的近期全球折叠屏智能手机追踪陈述&#xff0c;2023年第二季度全球折叠屏智能手机商场同比添加10%&#xff0c;达到210万部。该增幅与全球智能手机商场形成了鲜明对比&#xff0c;后者在同一季度出货量下降9%&#xff0c;达2.68亿部。估量智能手机商场…

Smtp4dev 虚拟SMTP电子邮件服务

Smtp4dev&#xff08;https://github.com/rnwood/smtp4dev&#xff09;用于开发和测试的虚拟SMTP电子邮件服务器。可以让你在测试应用程序时&#xff0c;无需向真实客户发送邮件&#xff0c;也无需使用特殊配置设置复杂的真实电子邮件服务器 dotnet tool install -g Rnwood.Smt…

Linux 安全 - SUID机制

文章目录 一、文件权限位二、SUID简介 一、文件权限位 &#xff08;1&#xff09; $ ls -l text.txt -rw-rw-r-- 1 yl yl 0 Sep 28 16:25 text.txt其中第一个字段-rw-rw-r–&#xff0c;我们可以把它分为四部分看&#xff1a; -rw-rw-r--&#xff08;1&#xff09;- &a…

Pygame中监控鼠标动作的方法

在Pygame中监控键盘按键的方法_pygame获取键盘输入-CSDN博客中提到&#xff0c;通过在while True循环中获取队列中事件的方法监控键盘动作。监控鼠标动作的方法与监控键盘动作的方法相同。 相关连接1 队列与事件的相关知识&#xff0c;请参考 Pygame中监控键盘按键的方法_pyg…

从技能需求到就业前景,了解前端和后端开发的优缺点和个人选择

文章目录 每日一句正能量一、引言前端开发后端开发 二、两者的对比分析三、技能转换和跨领域工作四&#xff1a;介绍全栈开发后记 每日一句正能量 命运决定的不是你的人生&#xff0c;能决定你人生的只有自己。 一、引言 前端和后端是Web开发中两个不可或缺的领域。前端开发主…

No131.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

vulnhub靶机-DC系列-DC-3

文章目录 信息收集漏洞查找漏洞利用SQL注入John工具密码爆破反弹shell 提权 信息收集 主机扫描 arp-scan -l可以用netdiscover 它是一个主动/被动的ARP 侦查工具。使用Netdiscover工具可以在网络上扫描IP地址,检查在线主机或搜索为它们发送的ARP请求。 netdiscover -r 192.1…

Linux或Centos查看CPU和内存占用情况_top只能查看对应的命令_如何查看具体进程---linux工作笔记062

一般我们都是用top去查看,但是top查看的结果,不能看出,具体是哪个程序占用的,这就很苦恼.. 其实如果有时间的话,再去专门看一下网络安全和linux脚本以及命令方面的,比较系统的看一下比较好.现在积累的都是工作中用到的,比较零散的知识. 如果用top,比如说这里的java,就只能知道…

云服务器租用价格表概览_阿里云腾讯云华为云

云服务器租用价格多少钱一年&#xff1f;阿腾云分享阿里云、腾讯云和华为云的云服务器租用价格表&#xff1a;阿里云2核2G服务器108元一年起、腾讯云2核2G3M带宽轻量服务器95元一年、华为云2核2G3M云耀L实例89元一年起&#xff0c;阿腾云分享更多关于云服务器租用价格明细&…

eNSP网络学习-v05

IP容量 ip地址一共是32位&#xff0c;/24就表示他的网络号是24位。 也就是说共有 2^&#xff08;32-24&#xff09;-2 个主机&#xff08;因为主机为全0和1的保留不用&#xff0c;所以需要减2&#xff09;&#xff0c;共254个ip。 /24&#xff1a;2的8次方-2 &#xff1a;254 …

安达发|APS生产排程软件给化工行业带来的价值

化工行业是一个涵盖了广泛的领域&#xff0c;包括石油化工、有机化工、无机化工、精细化工、生物化工等。 化工行业是指以化学工艺为基础&#xff0c;通过化学反应制取化学品的工业。根据生产工艺和产品性质&#xff0c;化工行业可以分为以下几类&#xff1a; 1. 石油化工&…