c#笔记整理 关于继承与多态等
【 塔 · 第 二 条 约 定 】
c#面向对象基础
整理private、protected、public、abstract等的异同
public 公有访问。不受任何限制。
private 私有访问。只限于本类成员访问,子类,实例都不能访问。
protected 保护访问。只限于本类和子类访问,实例不能访问
三者的对比:
- private和protected的共同点:外部都不可以访问。
 - private和protected的不同点:在同一类中可视为一样,但在继承中就不同了,private在派生类中不可以被访问,而protected可以。
 - public对任何类和成员都完全公开,无限制访问。
 - class 内默认为private。struct 内默认为public
eg: 
class music
{
    public string singer;
    protected int age;
    private int weight;
}
class palyer
{
     music obj = new music();
     obj.singer = sam;
     //obj.age = 21;  不能访问
    //obj.weight = 100;  不能访问 如果是子类则可以访问
}
- abstract类不能被实例化,它只提供其他类的继承的接口
 
整理有关继承、多态等概念
为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总是希望能够利用前人或自己以前的开发成果,同时又希望在
自己的开发过程中能够有足够的灵活性,不拘泥于复用的模块。C#这种完全面向对象的程序设计语言提供了两个重要的特性--
继承性inheritance 和多态性polymorphism。
继承是面向对象程序设计的主要特征之一,它可以让您重用代码,可以节省程序设计的时间。继承就是在类之间建立一种相交关系,使得
新定义的派生类的实例可以继承已有的基类的特征和能力,而且可以加入新的特性或者是修改已有的特性建立起类的新层次。
  现实世界中的许多实体之间不是相互孤立的,它们往往具有共同的特征也存在内在的差别。人们可以采用层次结构来描述这些实体之间的相似之处和不同之处。
最高层的实体往往具有最一般最普遍的特征,越下层的事物越具体,并且下层包含了上层的特征。
它们之间的关系是基类与派生类之间的关系。
为了用软件语言对现实世界中的层次结构进行模型化,面向对象的程序设计技术引入了继承的概念。一个类从另一个类派生出来时,
派生类从基类那里继承特性。派生类也可以作为其它类的基类。从一个基类派生出来的多层类形成了类的层次结构。
  注意:C#中,派生类只能从一个类中继承。这是因为,在C++中,人们在大多数情况下不需要一个从多个类中派生的类。从多个基类中派生一个类这往往会带来许多问题,从而抵消了这种灵活性带来的优势。
C#中,派生类从它的直接基类中继承成员:方法、域、属性、事件、索引指示器。除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员。
eg:(搜刮的栗子,看着挺好理解。)
using System ;
class Vehicle //定义交通工具(汽车)类
{
     protected int wheels ; //公有成员:轮子个数
     protected float weight ; //保护成员:重量
     public Vehicle( ){;}
     public Vehicle(int w,float g)
     {
        wheels = w ;
        weight = g ;
     }
     public void Speak( )
     {
        Console.WriteLine( "交通工具的轮子个数是可以变化的! " ) ;
     }
} ;
class Car:Vehicle //定义轿车类:从汽车类中继承
{
    int passengers ; //私有成员:乘客数
    public Car(int w , float g , int p) : base(w, g)
    {
        wheels = w ;
        weight = g ;
        passengers=p ;
    }
}//Vehicle 作为基类,体现了"汽车"这个实体具有的公共性质:汽车都有轮子和重量。Car 类继承了Vehicle 的这些性质,并且添加了自身的特性:可以搭载乘客。
C#中的继承符合下列规则:
继承是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。Object 类作为所有类的基类。
派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去已经继承的成员的定义。
构造函数和析构函数不能被继承。除此以外的其它成员,不论对它们定义了怎样的访问方式,都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。
派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。
类可以定义虚方法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。
派生类只能从一个类中继承,可以通过接吕实现多重继承。
隐藏基类成员
想想看,如果所有的类都可以被继承,继承的滥用会带来什么后果?类的层次结构体系将变得十分庞,大类之间的关系杂乱无章,对类的理解和使用都会变得十分困难。有时候,我们并不希望自己编写的类被继承。另一些时候,有的类已经没有再被继承的必要。C#提出了一个
- 密封类(sealedclass)的概念,帮助开发人员来解决这一问题。
密封类在声明中使用sealed修饰符,这样就可以防止该类被其它类继承。如果试图将一个密封类作为其它类的基类,C#将提示出错。 
理所当然,密封类不能同时又是抽象类,因为抽象总是希望被继承的。
在哪些场合下使用密封类呢?密封类可以阻止其它程序员在无意中继承该类。而且密封类可以起到运行时优化的效果。实际上,密封类中不可能有派生类。如果密封类实例中存在虚成员函数,该成员函数可以转化为非虚的,函数修饰符virtual 不再生效。
eg:
abstract class A
   {
       public abstract void F( ) ;
   }
   sealed class B: A
   {
       public override void F( )
       { // F 的具体实现代码 }
   }
  如果我们尝试写下面的代码
    class C: B{ }
  C#会指出这个错误,告诉你B是一个密封类,不能试图从B 中派生任何类。
  
- 使用 new 修饰符可以显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。
 
面向对象程序设计中的另外一个重要概念是多态性。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作用就体现出来了,这些对象不必是相同类型的对象。当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。如果这些对象都有同名方法,就可以调用每个对象的同名方法。
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。多态性通过派生类重载基类中的虚函数型方法来实现。
在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作、如何实现由系统负责解释。
“多态性”一词最早用于生物学,指同一种族的生物体具有相同的特性。在C#中,多态性的定义是:同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果。C#支持两种类型的多态性:
- 编译时的多态性
 
编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
- 运行时的多态性
 
运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中,运行时的多态性通过虚成员实现。
编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。
静多态
通过
- 函数重载
 - 运算符重载
 
实现
动态多态
通过
- 抽象类
 - 虚方法
 
实现
虚方法
当类中的方法声明前加上了virtual修饰符,我们称之为虚方法,反之为非虚。使用了virtual修饰符后,不允许再有static, abstract,或override 修饰符。
eg:带有虚方法的类
using System ;
public class DrawingBase
{
    public virtual void Draw( )
    {
        Console.WriteLine("这是一个虚方法!") ;
    }
}
虚方法与非虚方法的区别
using System ;
class A
{
   public void F( )
   {
       Console.WriteLine("A.F") ;
   }
   public virtual void G( )
   {
       Console.WriteLine("A.G") ;
   }
}
class B: A
{
   new public void F( )
   {
       Console.WriteLine("B.F") ;
   }
   public override void G( )
   {
       Console.WriteLine("B.G") ;
   }
}
class Test
{
   static void Main( )
   {
      B b = new B( ) ;
      A a = b;
      a.F( ) ;
      b.F( ) ;
      a.G( ) ;
      b.G( ) ;
   }
}
A 类提供了两个方法:非虚的F 和虚方法G 。类B 则提供了一个新的非虚的方法F, 从而覆盖了继承的F; 类B 同时还重载了继承的方法G 。那么输出应该是:A.F B.F B.G B.G
注意到本例中,方法a.G(实际调用了B.G,而不是A.G,这是因为编译时值为A,但运行时值为B ,所以B 完成了对方法的实际调用。在派生类中对虚方法进行重载
注意:
普通的方法重载指的是:类中两个以上的方法(包括隐藏的继承而来的方法),取的名字相同,只要使用的参数类型或者参数个数不同,编译器便知道在何种情况下应该调用哪个方法。
而对基类虚方法的重载是函数重载的另一种特殊形式。在派生类中重新定义此虚函数时,要求的是方法名称,返回值类型、参数表中的参数个数、类型顺序都必须与基类中的虚函数完全一致。在派生类中声明对虚方法的重载,要求在声明中加上override 关键字,而且不能有new,static 或virtual 修饰符。
多态性的栗子:
eg:
using System ;
class Vehicle//定义汽车类
{
   public int wheels; //公有成员轮子个数
   protected float weight; //保护成员重量
   public Vehicle(int w,float g)
   {
       wheels = w;
       weight = g;
   }
   public virtual void Speak( )
   {
      Console.WriteLine( " the w vehicle is speaking!" ) ;
   }
};
class Car:Vehicle //定义轿车类
{
   int passengers; //私有成员乘客数
    public Car(int w,float g,int p) : base(w,g)
    {
        wheels = w;
        weight = g;
        passengers = p;
    }
    public override void Speak( )
    {
       Console.WriteLine( " The car is speaking:Di-di!" ) ;
    }
}
class Truck:Vehicle //定义卡车类
{
    int passengers; //私有成员乘客数
    float load; //私有成员载重量
    public Truck (int w,float g,int p, float l) : base(w,g)
    {
        wheels = w;
        weight = g;
        passengers = p;
        load = l;
    }
    public override void Speak( )
    {
        Console.WriteLine( " The truck is speaking:Ba-ba!" ) ;
    }
    public static void Main( )
    {
        Vehicle v1 = new Vehicle(0,0 ) ;
        Car c1 = new Car(4,2,5) ;
        Truck t1 = new Truck(6,5,3,10) ;
        v1.Speak( ) ;
        v1 = c1;
        v1.Speak( ) ;
        c1.Speak( ) ;
        v1 = t1;
        v1.Speak( ) ;
        t1.Speak( ) ;
    }
}
Vehicle 类中的Speak 方法被声明为虚方法,那么在派生类中就可以重新定义此方法。
在派生类Car 和Truck 中分别重载了Speak 方法,派生类中的方法原型和基类中的方法原型必须完全一致。
在Test 类中,创建了Vehicle 类的实例v1, 并且先后指向Car 类的实例c1 和Truck 类的实例t1。
运行该程序结果应该是:
The Vehicle is speaking!
The car is speaking:Di-di!
The car is speaking:Di-di!
The truck is speaking:Ba-ba!
The truck is speaking:Ba-ba!
- 这里,Vehicle 类的实例v1 先后被赋予Car类的实例c1, 以及Truck类的实例t1的值。在执行过程中,v1先后指代不同的类的实例,从而调用不同的版本。这里v1 的Speak 方法实现了多态性,并且v1.Speak究竟执行哪个版本,不是在程序编译时确定的,而是在程序的动态运行时,根据v1 某一时刻的指代类型来确定的,所以还体现了动态的多态性。
 
c#笔记整理 关于继承与多态等的更多相关文章
- (C/C++学习笔记) 十八. 继承和多态
		
十八. 继承和多态 ● 继承的概念 继承(inheritance): 以旧类为基础创建新类, 新类包含了旧类的数据成员和成员函数(除了构造函数和析构函数), 并且可以派生类中定义新成员. 形式: cl ...
 - 《java JDK7 学习笔记》之继承与多态
		
1.面向对象中,子类继承父类,避免重复的行为定义,不过并非为了避免重复定义行为就使用继承.应该正确判断使用继承的时机及继承之后灵活的运用多态,才是学习继承时的重点. 2.程序代码重复在程序设计上,就是 ...
 - Java学习笔记——封装、继承和多态
		
先说说封装: 用new 一条狗来举个例子: public class Dog { //私有化字段 private String name; private int age; //无参构造 Dog(){ ...
 - C#学习笔记7:多态是面向对象的三大特征(封装、继承、多态)之一
		
多态: 多态是面向对象的三大特征(封装.继承.多态)之一. 什么是多态? 一个对象表现出多种状态. 多态的实现方法: 1.虚方法: 2.抽象方法: 3.接口. PS:New 关键词可以隐藏父类的方法. ...
 - Java学习笔记--继承和多态(中)
		
1.通过继承来开发超类(superclass) 2.使用super 关键词唤起超类的构造方法 3.在超类中覆盖方法 4.区分override和overload 5.在Object类中探索toStrin ...
 - Java学习笔记 07 接口、继承与多态
		
一.类的继承 继承的好处 >>使整个程序架构具有一定的弹性,在程序中复用一些已经定义完善的类不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性 继承的基本思想 >>基 ...
 - C# 读书笔记之继承与多态
		
1.1继承与多态的基本概念 1.1.1 继承和多态 继承是面向对象程序设计的主要特征之一,允许重用现有类(基类,亦称超类.父类)去创建新类(子类,亦称派生类)的过程.子类将获取基类的所有非私有数据和行 ...
 - Java学习笔记(三)——封装、继承、多态
		
一.封装 概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 实现步骤: 修改属性的可见性——设为private. 创建getter/se ...
 - Java类的继承与多态特性-入门笔记
		
相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...
 
随机推荐
- Ansible实现主备模式的高可用(Keepalived)
			
前言 Ansible是一款极其简单的IT自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置.批量程序 ...
 - php 将富文本编辑后的内容取出
			
背景:项目中用了富文本编辑器,讲写完的内容存入了数据库,但是取出的时候因为有些展示地方并不需要样式,只想获取到内容,所以需要将带了html编码的信息解析出来. 原始信息如下 [task_desc] = ...
 - git找回本地误删的文件或文件夹
			
一:首先,我们先用git status 看看工作区的变化 application/Admin/Conf/config.php 如果要恢复文件记住这个 application 如果要恢复文件夹记住这个工 ...
 - Hadoop MapReduce自定义数据类型
			
一 自定义数据类型的实现 1.继承接口Writable,实现其方法write()和readFields(), 以便该数据能被序列化后完成网络传输或文件输入/输出: 2.如果该数据需要作为主键key使用 ...
 - Ubuntu中 MySQL 的中文编码问题
			
使用Ubuntu在安装好MySQL数据库之后,如果直接创建数据库,再创建数据表,那么是无法向字段插入中文的,会报Incorrect string value错误. c实现编码设置的两种方法: (1)动 ...
 - ISAP学习笔记
			
学完了ISAP,感觉心情舒畅,毕竟ISAP比Dinic好一点. 说到底ISAP其实是Dinic(不熟悉Dinic的人去我的博客找猴子课堂----最大流与最小割(看看思想),已经置顶)优化版,熟悉的人知 ...
 - C# string 转 byte[]
			
string 转 byte[] /// <summary> /// string 转 byte /// </summary> /// <param name=" ...
 - SQL 备忘录
			
都兼容 MySQL 查看表结构:DESC ${table_name} 查看建表语句:SHOW CREATE TABLE ${table_name} 表增加列:ALTER TABLE ${table_ ...
 - WPF程序,运行时,结束时,要运行的操作(自动保存,检查单程序)
			
/// <summary> /// App.xaml 的交互逻辑 /// </summary> public partial class App : Application { ...
 - 北京Uber优步司机奖励政策(3月9日)
			
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...