六、C# 派生

时间:2021-10-12 01:34:52
派生
对一个现有的类型进行扩展,以便添加更多的功能,或者对现有的类型的操作进行重写。
 
比如可以将两个类都适用的方法和属性,用一个新的类进行重构,两个类再分别继承这个类。
 
定义一个派生类时,要在类标识符后面添加一个冒号,接着添加基类名称。
 
可以多重继承,且继承链是没有限制的,每个派生类都拥有由其所有基类公开出来的全部成员。
 
注:所有的类都派生自object类。
 
1、基类型和派生类型之间的转型
由于派生建立了一个属于关系,所以总是可以将一个派生类型直接赋值给一个基类型。
 
隐式转换:可以将一个派生类的引用直接赋值给一个基类对象。不会发生数据丢失。
 
显式转换:语法格式与基本类型一致,有可能发生数据的丢失等。
 
隐式转型为基类不会实例化一个新的实例。相反,同一个实例会被引用为基类型,而它现在
提供的功能(也就是可访问的成员)是基类型的。
类似地,将基类向下转型为派生类,会引用更具体的类型,类型可用的操作也会进行扩展,但这
种转换是有限制的,实际被实例化的类型必须是要转换成的目标类型的一个实例。
注:从派生类转换为基类只会保留基类中可访问的成员,不能保留子类中可访问的成员。
代码:
     class Program
{
static void Main(string[] args)
{
Contact contact = new Contact();
PdaItem pda = new PdaItem();
pda = contact;
}
}
public class PdaItem
{
public string Name { set; get; }
public DateTime LastUpdated { set; get; }
}
public class Contact : PdaItem
{
public string Address { set; get; }
public string Phone { set; get; }
}
2、定义自定义转换
类型间的转并不限于单一继承的类型。完全不相关的类型相互之间也能进行转换。这里的关键在于在两个
类型之间提供一个转型运算符。C#允许类型包含显式或隐式转型运算符。
implicit operator 类型(参数)
{
 
}
explicit operator 类型(参数)
{
 
}
代码:
     class Program
{
static void Main(string[] args)
{
PdaItem pda = new PdaItem("name1", DateTime.Now);
Contact contact = new Contact("name2", DateTime.Now.AddDays(), "beijing", "");
pda = contact;
Person person = new Person("PersonName1", "tianjin");
contact = person;
}
}
public class PdaItem
{
public PdaItem()
{
}
public PdaItem(string pName, DateTime pLastUpdated)
{
Name = pName;
LastUpdated = pLastUpdated;
}
public string Name { set; get; }
public DateTime LastUpdated { set; get; }
}
public class Contact : PdaItem
{
public Contact()
{
}
public Contact(string pName, DateTime pLastUpdated, string pAddress, string pPhone)
: base(pName, pLastUpdated)
{
Address = pAddress;
Phone = pPhone;
}
public string Address { set; get; }
public string Phone { set; get; }
}
public class Person
{
public Person(string pName, string pAddress)
{
Name = pName;
Address = pAddress;
}
public string Name { set; get; }
public string Address { set; get; }
/// <summary>
/// 隐式转换
/// </summary>
/// <param name="person"></param>
/// <returns></returns>
public static implicit operator Contact(Person person)
{
Contact c = new Contact();
c.Name = person.Name;
c.Address = person.Address;
c.LastUpdated = DateTime.Today;
c.Phone = "";
return c;
}
}
3、访问修饰符
在派生类当中可以访问 public、protected修饰的基类成员。
 
4、扩展方法
扩展方法的一个特点是,它们都是静态方法,不可被继承。
 
5、单一继承
C#是一种单一继承的编程语言,C#编译成的CIL语言也是一样。
在极少数需要多重继承结构的情况下,一般的解决方案是使用聚合,而不是继承第二个包含这个类的实例的类。
声明一个主要基类,然后派生一个出一个新的类。再定义第二个基类(只是名义上的),将第二个基类的一个对象作为派生类的一个字段,所有第二个基类的成员,都在派生类中重写。通过操作一个基类的对象实例来完成。
派生类将调用委托给字段。
除了因为委托而增加的复杂性,另一个缺点在于,在第二个基类上新增的任何方法
都需要人工添加到派生类中,否则派生类无法公共新增的功能(第二个基类上的功能需要操作第一个
基类中的成员和派生中的成员时)。
代码:
     class Program
{
static void Main(string[] args)
{
Contact p = new Contact("xxm", DateTime.Now, );
Console.WriteLine(p.GetSex());
Console.ReadLine(); }
}
public class PdaItem
{
public PdaItem()
{
}
public PdaItem(string pName, DateTime pLastUpdated)
{
Name = pName;
LastUpdated = pLastUpdated;
}
public string Name { set; get; }
public DateTime LastUpdated { set; get; }
}
public class Person
{
public Person(int pSex)
{
Sex = pSex;
}
public int Sex { set; get; }
public string GetSex()
{
switch (Sex)
{
case :
return "女";
case :
return "男";
default:
return "未定义";
}
} }
public class Contact : PdaItem
{
public Contact()
{
}
public Contact(string pName, DateTime pLastUpdated, int sex)
: base(pName, pLastUpdated)
{
person = new Person(sex);
}
public Person person { set; get; }
public int Sex
{
set { person.Sex = value; }
get { return person.Sex; }
}
public string GetSex()
{
switch (Sex)
{
case :
return Name + "," + "女" + "," + LastUpdated;
case :
return Name + "," + "男" + "," + LastUpdated; ;
default:
return Name + "," + "未定义" + "," + LastUpdated; ;
}
}
}
6、密封类
把类标记为sealed修饰。
不能从密封类中派生出其他类,也就是不能作为基类被继承。
 
基类的重写
 
在派生类中可以访问基类的所有public、protected成员。
可以重写(替换)基类中的实现。
 
1、virtual修饰符
 
C#支持重写实例方法和属性,但不支持重写字段或者任何静态成员。
为了进行重写,要求在基类和派生类中都显式地执行一个操作。
在基类中,必须将允许重写的每个成员标记为virtual。
在派生类中使用override。
virtual标志着一个方法或属性可以在派生类中被替换(重写)。
 
重载一个成员,会造成“运行时”调用最底层的或者说派生得最远的实现。
 
虚方法只提供了默认实现,这种实现可由派生类完全重写。
注:只有实例成员才可以 是virtual的。static virtual是无意义的。也不允许出现。
     class Program
{
static void Main(string[] args)
{
PdaItem p = new PdaItem("pname", DateTime.Now.AddDays(-));
Contact c = new Contact("name1", DateTime.Now);
p = c;
p.Name = "name1";
Console.WriteLine(p.Name); }
}
public class PdaItem
{
public PdaItem()
{
}
public PdaItem(string pName, DateTime pLastUpdated)
{
Name = pName;
LastUpdated = pLastUpdated;
}
public virtual string Name { set; get; } public DateTime LastUpdated { set; get; }
} public class Contact : PdaItem
{
public override string Name
{
get
{
return FirtstName;
}
set
{
FirtstName = value + " from Contact";
}
}
public string FirtstName;
public Contact()
{
}
public Contact(string pName, DateTime pLastUpdated)
: base(pName, pLastUpdated)
{ } }
输出:name1 from Contact;
2、new 运算符
 
在基类中的成员没有被声明为virtual时,如果在派生类中声明一个相同签名的成员时。
需要使用new修饰符(如果不指定override 和new,默认为new,从而维持了版本的安全性)。
使用new修饰符,它在基类面前隐藏了派生类的重新声明的成员。在这种情况下,不是调用派生得
最远的成员,相反,基类的成员会搜索继承链,找到使用了new修饰符的那个成员之前的成员,然后
调用该成员。如果继承链中仅包含两个类,就会使用基类的成员,感觉就像是派生类没有重写那个成
员。
注:以上针对的都是基类的对象的搜索。派生类对象的查找以其自身为标准,寻找自己的派生类中的重写之类的。
代码:
     class Program
{
static void Main(string[] args)
{
PdaItem p = new PdaItem("pname", DateTime.Now.AddDays(-));
Contact c = new Contact("name1", DateTime.Now);
p = c;
p.Name = "name1";
Console.WriteLine(p.Name); }
}
public class PdaItem
{
public PdaItem()
{
}
public PdaItem(string pName, DateTime pLastUpdated)
{
Name = pName;
LastUpdated = pLastUpdated;
}
public string Name { set; get; } public DateTime LastUpdated { set; get; }
} public class Contact : PdaItem
{
public new string Name
{
get
{
return FirtstName;
}
set
{
FirtstName = value + " from Contact";
}
}
public string FirtstName;
public Contact()
{
}
public Contact(string pName, DateTime pLastUpdated)
: base(pName, pLastUpdated)
{ } }
输出:name1
3、sealed修饰符
virtual也可以通过sealed修饰符,从而禁止子类重写声明为virtual的基类成员。
在子类的使用了override重写的方法(任何用override修饰的成员会自动成为virtual成员,可以通过sealed修饰,防止被此类的子类继续重写。
 
4、base成员
重新声明一个成员时,开发者经常需要调用基类的一个成员。
通过base.成员,访问基类中的成员(通常用来访问被重写的成员)。
 
5、构造器
实例化一个派生类时,运行时 首先调用基类的构造器,以避免基类构造器被绕过。
假如基类没有默认构造器,就是需要在子类的构造器显式调用
public aaaa(string name):base(name)
{
 
}
6、抽象类
abstract 修饰。
抽象类是仅供派生的类。无法实例化一个抽象类,只能实例化从它派生的类。不抽象、可直接实例休的类称为具体类。
 
抽象类代表抽象的实体。其抽象成员定义了从抽象实例派生的一个对象应包含什么东西,但它们不能包含实现。
一个类要想从抽象类成功地派生,它必须为抽象基类中的抽象方法提供具体的实现。
抽象类的主要特征在于它包含抽象成员。抽象成员是不具有实现的一个方法或属性,其作用是强制所有派生类提供实现。
 
由于抽象成员应当是要被重写的,因此这类成员会自动成为virtual成员,而且不能这样显式地声明virtual。
抽象成员不能是private的,否则派生类看不见它们。
 
注:抽象类可以包含非抽象成员。
     class Program
{
static void Main(string[] args)
{
PdaItem p;
Contact c = new Contact("contact name");
p = c;
Console.WriteLine(p.Name +","+ p.GetSummary()); Appointment ap = new Appointment("appointment name");
p = ap;
Console.WriteLine(p.Name + "," + p.GetSummary());
Console.ReadLine(); }
}
public abstract class PdaItem
{
public PdaItem()
{ }
public PdaItem(string pName)
{
Name = pName;
}
public virtual string Name { set; get; }
public abstract string GetSummary();
} public class Contact : PdaItem
{
public new string Name
{
get
{
return FirtstName;
}
set
{
FirtstName = value + " from Contact";
}
}
public string FirtstName;
public Contact()
{
}
public Contact(string pName)
: base(pName)
{ }
public override string GetSummary()
{
return "GetSummary() from Contact";
} }
public class Appointment : PdaItem
{
public new string Name
{
get
{
return FirtstName;
}
set
{
FirtstName = value + " from Appointment";
}
}
public string FirtstName;
public Appointment()
{
}
public Appointment(string pName)
: base(pName)
{ }
public override string GetSummary()
{
return "GetSummary() from Appointment";
} }
输出:
contact name,GetSummary() from Contact
appointment name,GetSummary() from Appointment
 
7、多态性
倘若同一个成员签名的实现在两个或多个类之间发生变化,就会获得面向对象程序设计的一个关键特性:多态性。
多态性(运行时多态)是指同一个签名可以有多个实现这一事实。
 
抽象成员是实现多态性的一个手段。(同理,虚成员也具有这一功效)。
代码:
8、所有类都从System.Object派生
 
System.Object的成员
Equals()
GetHashCode()
GetType()
ReferenceEquals()
ToString()
Finalize()
MemberwiseClose()
 
9、使用is运算符验证基础类型
对象 is 类型
is并非仅仅是检查数据能成功转型,还会检查底层对象本身是否是真的是一上对应的类型。
运算符能判断基础类型。
10、使用as运算符进行转换
对象   as  类型 
 
注:使用as运算符,在转换无效的前提下,会赋值null
 
is运算符相较于as运算符的一个优点在于,后者不能成功判断基础类型。后者允许在一个继承链上向上或向下转型为
支持转型运算符的类型。
 
 

六、C# 派生的更多相关文章

  1. androd输入管理系统机制解析

     android的输入管理系统主要完成按键.触摸板.鼠标等输入设备的事件输入,功能包括,输入设备的事件输入及向焦点窗口和焦点视图的事件派发,事件的插入,事件的过滤,事件的拦截等功能. 整个输入系统 ...

  2. Core官方DI解析&lpar;3&rpar;-ServiceCallSite&period;md

    上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...

  3. C&plus;&plus;进阶笔记

    思想原则: 以类为例,类最终要处理的是数据,方法只是过程,最终要改变的是private中的数据成员状态.程序设计也是如此,要的是数据. 一.const的作用 const定义变量:定义了一个不可修改的常 ...

  4. 【C&plus;&plus; 实验六 继承与派生】

    实验内容 1. 某计算机硬件系统,为了实现特定的功能,在某个子模块设计了 ABC 三款芯片用于 数字计算.各个芯片的计算功能如下: A 芯片:计算两位整数的加法(m+n).计算两位整数的减法(m-n) ...

  5. SQL Server进阶(六)表表达式--派生表、公用表表达式&lpar;CTE&rpar;、视图和内联表值函数

    概述 表表达式是一种命名的查询表达式,代表一个有效地关系表.可以像其他表一样,在数据处理中使用表表达式. SQL Server支持四种类型的表表达式:派生表,公用表表达式,视图和内联表值函数. 为什么 ...

  6. 第三十六章、PyQt输入部件:QAbstractSpinBox派生类QSpinBox、 QDoubleSpinBox、QDateTimeEdit、QDateEdit和QTimeEdit

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 Designer输入部件中的Spin B ...

  7. Python之路【第六篇】python基础 之面向对象进阶

    一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象  和  issubclass(su ...

  8. Python之路【第六篇】python基础 之面向对象(一)

    一.三大编程范式 1.面向过程编程 2.函数式编程 3.面向对象编程 二.编程进化论 1.编程最开始就是无组织无结构,从简单控制流中按步写指令 2.从上述的指令中提取重复的代码块或逻辑,组织到一起(比 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 &lpar;30&rpar; ------ 第六章 继承与建模高级应用之多对多关联

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章  继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...

随机推荐

  1. 2、软件设计师要阅读的书籍 - IT软件人员书籍系列文章

    软件设计师在项目组中的地位比软件工程师相对要高一些.但是他们所要阅读的书籍差别还是比较大的.同样的,软件设计师也要阅读比较多的书籍,以能够完成项目的任务为目的,同时还要提高自身在项目组中的竞争地位,而 ...

  2. 哇 真的是一个好插件!!!Sublime Text编辑文件后快速刷新浏览器

    http://9iphp.com/web/html/sublime-text-refresh-browser.html这篇博文咯 来源:[Tips]Sublime Text编辑文件后快速刷新浏览器 - ...

  3. linux运维中的命令梳理(四)

    ----------管理命令---------- ps命令:查看进程 要对系统中进程进行监测控制,查看状态,内存,CPU的使用情况,使用命令:/bin/ps (1) ps :是显示瞬间进程的状态,并不 ...

  4. Leetcode 235 Lowest Common Ancestor of a Binary Search Tree 二叉树

    给定一个二叉搜索树的两个节点,找出他们的最近公共祖先,如, _______6______ / \ ___2__ ___8__ / \ / \ 0 4 7 9 / \ 3 5 2和8的最近公共祖先是6, ...

  5. 设计模式 Template Method模式 显示程序猿的一天

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/26276093 不断设计模式~ Template Method模式 老套路,看高清 ...

  6. SpannableString可以被点击的文字

    1 TextView tv= (TextView) findViewById(R.id.textview_z); String text="一段可以被点击点击的文字,文字可以变成图片&quo ...

  7. 25&period; leetcode 217&period; Contains Duplicate

    217. Contains Duplicate Given an array of integers, find if the array contains any duplicates. Your ...

  8. chrome console的使用 : 异常和错误的处理 – Break易站

    本文内容来自:chrome console的使用 : 异常和错误的处理 – Break易站 利用 Chrome DevTools 提供的工具,您可以修复引发异常的网页和在 JavaScript 中调试 ...

  9. Android颜色配置器

    一.Android Color设置 1.在xml文件中 想设置颜色直接设置background的属性或者其他的color属性.随便设置一个颜色如#000,再点击左边的颜色方块,弹出颜色选择器选择颜色 ...

  10. FileZilla连接腾讯云Centos7

    现在需要使用ftp快速上传资料去云机备份, 于是想到FileZilla. 生成密匙文件 登录腾讯云--ssh密匙 FileZilla Client 导入密匙文件 填写登录信息 连接 另外记得开放22端 ...