【 塔 · 第 二 条 约 定 】

c#面向对象基础

整理private、protected、public、abstract等的异同

  1. public 公有访问。不受任何限制。

  2. private 私有访问。只限于本类成员访问,子类,实例都不能访问。

  3. 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; 不能访问 如果是子类则可以访问
}
  1. 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#中的继承符合下列规则:

  1. 继承是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。Object 类作为所有类的基类。

  2. 派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去已经继承的成员的定义。

  3. 构造函数和析构函数不能被继承。除此以外的其它成员,不论对它们定义了怎样的访问方式,都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。

  4. 派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。

  5. 类可以定义虚方法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。

  6. 派生类只能从一个类中继承,可以通过接吕实现多重继承。

  7. 隐藏基类成员

  想想看,如果所有的类都可以被继承,继承的滥用会带来什么后果?类的层次结构体系将变得十分庞,大类之间的关系杂乱无章,对类的理解和使用都会变得十分困难。有时候,我们并不希望自己编写的类被继承。另一些时候,有的类已经没有再被继承的必要。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#中,运行时的多态性通过虚成员实现。

编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。

静多态

通过

  1. 函数重载
  2. 运算符重载

实现

动态多态

通过

  1. 抽象类
  2. 虚方法

实现

虚方法

当类中的方法声明前加上了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#笔记整理 关于继承与多态等的更多相关文章

  1. (C/C++学习笔记) 十八. 继承和多态

    十八. 继承和多态 ● 继承的概念 继承(inheritance): 以旧类为基础创建新类, 新类包含了旧类的数据成员和成员函数(除了构造函数和析构函数), 并且可以派生类中定义新成员. 形式: cl ...

  2. 《java JDK7 学习笔记》之继承与多态

    1.面向对象中,子类继承父类,避免重复的行为定义,不过并非为了避免重复定义行为就使用继承.应该正确判断使用继承的时机及继承之后灵活的运用多态,才是学习继承时的重点. 2.程序代码重复在程序设计上,就是 ...

  3. Java学习笔记——封装、继承和多态

    先说说封装: 用new 一条狗来举个例子: public class Dog { //私有化字段 private String name; private int age; //无参构造 Dog(){ ...

  4. C#学习笔记7:多态是面向对象的三大特征(封装、继承、多态)之一

    多态: 多态是面向对象的三大特征(封装.继承.多态)之一. 什么是多态? 一个对象表现出多种状态. 多态的实现方法: 1.虚方法: 2.抽象方法: 3.接口. PS:New 关键词可以隐藏父类的方法. ...

  5. Java学习笔记--继承和多态(中)

    1.通过继承来开发超类(superclass) 2.使用super 关键词唤起超类的构造方法 3.在超类中覆盖方法 4.区分override和overload 5.在Object类中探索toStrin ...

  6. Java学习笔记 07 接口、继承与多态

    一.类的继承 继承的好处 >>使整个程序架构具有一定的弹性,在程序中复用一些已经定义完善的类不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性 继承的基本思想 >>基 ...

  7. C# 读书笔记之继承与多态

    1.1继承与多态的基本概念 1.1.1 继承和多态 继承是面向对象程序设计的主要特征之一,允许重用现有类(基类,亦称超类.父类)去创建新类(子类,亦称派生类)的过程.子类将获取基类的所有非私有数据和行 ...

  8. Java学习笔记(三)——封装、继承、多态

    一.封装 概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 实现步骤: 修改属性的可见性——设为private. 创建getter/se ...

  9. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

随机推荐

  1. 使用apt-get install时如何指定安装版本

    命令语法如下: sudo apt-get install package=version 例如: sudo apt-get install samba=2:4.4.5+dfsg-2ubuntu6

  2. 微信小程序数据分析之自定义分析

    在小程序后台,微信已经提供了强大的数据分析功能,包括实时统计.访问分析.来源分析和用户画像功能,可以说对一般的数据分析已经完全足够了,但有时应用需要做一些更加精准的数据分析,比如具体到某一个页面的分享 ...

  3. java的值传递机制

    一.练习:编写Java程序,将二维数组中的行列互调显示出来. 代码1为自己编写: package com.xxgpra.CH6; public class Hangliehudiao_pra4 { p ...

  4. Celery的基本使用

    Celery 1.什么是Celery Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度. 用Python写的执行 定时任务和异步任务的框 ...

  5. git小技巧之分支、关联远程仓库、回滚、解决.gitignore不生效等

    1.分支管理 新建并切换分支:git checkout -b <name>新建本地分支并关联到远程分支git checkout -b myRelease origin/Release合并某 ...

  6. JZ2440开发板:用按键点亮LED灯(学习笔记)

    本文是对韦东山嵌入式第一期学习的记录之一,如有您需要查找的信息,可以继续往下阅读. 想要用按键点亮LED灯,就需要知道按键和LED灯的相关信息,这样才可以进行之后的操作.阅读JZ2440的原理图,可以 ...

  7. Struts2获取Servlet的api的两种方式,解决ParameterAware过时的问题

    servlet API通过ActionContext进行获取 Struts2对HttpServletRequest,HttpSession和ServletContext进行了封装,构造了3个Map对象 ...

  8. springBoot整合ecache缓存

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. ehcache提供了多种缓存策略,主要分为内存和磁盘两级,所以无需担心 ...

  9. APP如何发布到Google play 商店

    APP如何发布到Google play 商店?以及有哪些需要注意的点 2015-05-13 10:07 19773人阅读 评论(1) 收藏 举报  分类: iPhone游戏开发(330)  链接:ht ...

  10. 长沙Uber优步司机奖励政策(1月4日~1月10日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...