现在的位置: 首页 > 综合 > 正文

关于面向对象的理解

2014年12月11日 ⁄ 综合 ⁄ 共 13370字 ⁄ 字号 评论关闭

面向对象的三大特征:继承、封装、多态

C#中的虚方法,抽象类,重写,隐藏,重载的区别与理解

1、   如果父类方法没有加virtual关键字,即不是一个虚方法,则在子类中只能隐藏基类方法

(new),而不能覆盖(override)。

2、如果父类方法加了virtual关键字,即它是一个虚方法,在子类中一样可以隐藏(new)。

3、如果子类实现了父类相同的方法(相同的方法名称及签名),而没有new,在编译时会报警,但

编译仍然能够通过!

4、调用父类方法:base.方法名()

5、abstract类是一个抽象类,不能被实例化,只能继承

6、最后讲讲重载(overload):是在同一个类中的两个或两个以上的方法,拥有相同的方法

名,函数类型也相同,但是参数却不相同,最常见的重载的例子就是类的构造函数。

 

 

实验例子如下:

 

1、虚方法的概念:

                         类中的方法声明前加上了virtual 修饰符,我们称之为虚方法;

                        如:  class A

                                              {

                                                    public virtual void F(){} //虚方法

                       }

                            virtual修饰符表明:该基类(本例中指A类)的派生类(本例中指B类)可以

重写该方法(本例中指方法F())。

                                          如:  class B:A

                                                        {

                                                               public override void F(){} //派生类B重写类A的虚

方法F()

}

 

                与之相对的,没有用virtual 修饰符,我们称之为非虚方法。

1.隐藏

无论父类方法有没有用virtual修饰符,都可以在子类隐藏父类方法,写法如下

  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");}

         new public void G( ){ Console.WriteLine("B.G");}

    }

  class Test

    {

         static void Main( )

           {

               b=new B( );

               a=b;

               a.F( ); //值为A.F

               b.F( ); //值为B.F

               a.G( ); //值为A.G              

               b.G( ); //值为B.G

           }

    }

如果要继承父类代码,可以用base.方法名()来调用

 

2.重写

(1)重写的概念:

是子类(即派生类)的方法覆盖父类(即基类)的虚方法。

(2)重写的要求:三相同:

         a.方法名称相同

         b.参数列表相同

         c.返回值类型相同

         一句话,只需重写代码体的内容!

(3)重写声明不能更改虚方法的可访问性:重写方法和虚方法必须具有相同的访问级修饰符。例如:虚方法为public的,重新方法也必须是public的。

 

(4)可以重写基方法:必须是虚拟的(virtual)、抽象的(abstract)或重写的(override)。(非虚方法或静态方法是不可以重写的)

(5)不能使用下列修饰符修改重写(override)方法(即该方法中含有override关键字):new、static、virtual、abstract

如:new public override void outwork () //这样写是不可以的

{

      MessageBox.Show("子类的子类(override)下班");

}

(6)重写属性:重写的属性必须与继承属性有完全相同的访问修饰符、类型和属性名,并且重写属性必须是虚拟的(virtual)、抽象的(abstract)或是重写的(override)。

(7)new关键字和override关键字比较:

                        如果使用override重写xx方法,通过父类引用一样只能看到重写后的方法; override重写的是虚方法,那么就只剩下重写以后的方法,原来的方法被覆盖了。

 

 

如果使用new隐藏xx方法,父类子类引用各自对应方法;

new隐藏基类的方法,那么基类的方法和当前类的方法同时存在只是被隐藏了。

总结:override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已。

举例说明:

例一:

  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=new B( );

               a=b;

               a.F( ); //值为A.F

               b.F( ); //值为B.F

               a.G( ); //值为B.G,因为虚方法G()被重写了

               b.G( ); //值为B.G

           }

    }

例二:

class  

   

      public   virtual   void   F()     Console.WriteLine("A.F");    

   

  class B:  

   

      public   override   void   F()     Console.WriteLine("B.F");    

   

  class C:  

   

      new   public   virtual   void   F()     Console.WriteLine("C.F");    

   

  class D:  

   

      public   override   void   F()     Console.WriteLine("D.F");    

   

  class Test  

   

      static   void   Main()  

   

             

           new D();  

           d;

           d;

           d;                

           a.F();  //值为B.F 

           b.F();  //值为B.F

           c.F();  //值为D.F 

           d.F();  //值为D.F 

         

  }

例三:abstract和override使用方法:注:只有当类是abstract时才可以声明abstract方法;

    abstract class Animal

    {

        public abstract void Drink();

        public abstract void GotoBed();

    }

    class Dog Animal

    {

        public override void Drink()

        {

            MessageBox.Show("小狗喝水");

        }

        public override void GotoBed()

        {

            MessageBox.Show("小狗睡觉");

        }

        public override string ToString()//也可:public new string ToString()

        {

            return "小狗";

        }

    }

 

总结:

Public abstract void pay();           abstract方法没有方法实现,必须继承

Public sealed override void pay(){}  sealed方法必须是重写父类的方法

Public static void pay(){}               static方法通过类名访问

Public virtual void pay(){}              virtual方法子类可以对其override或new

Public new void pay(){}                父类的方法pay不一定是virtual也可以为非虚方法

Public override void pay(){}             父类的方法pay一定要是virtual

 

例四:new、abstract、virtual、override关键字的使用代码示例:

public abstract class People //abstract说明类People是一个抽象类不能被实例的,只能被继承

    {

        public People()//构造函数

         {

         }

 

        public void Work() //非虚方法

         {

            MessageBox.Show("开始工作!");

         }

 

        public virtual void GetOffWork() //虚函数,说明此方法可以被子类重写覆盖(override)

         {

            MessageBox.Show("下班啦!");

         }

    }

 

public class Manage:People //继承Popele类

    {

        public Manage()//构造函数

         {

         }

        new public void Work()

                      

         {

            base.Work(); //调用基类Popele的方法。显示“开始工作”

         }

 

        public override void GetOffWork() //重写覆盖people类的方法

         {

            MessageBox.Show("管理员下班啦");

         }

C#中重写(override)和覆盖(new)的区别

Posted on 2012-04-14 13:16
祥叔
阅读(5386) 评论(11)编辑收藏

重写

用关键字 virtual 修饰的方法,叫虚方法。可以在子类中用override 声明同名的方法,这叫“重写”。相应的没有用virtual修饰的方法,我们叫它实方法。
重写会改变父类方法的功能。
看下面演示代码:
复制代码
#region 重写

public class C1
{
    public virtual string GetName()
    {
        return "叔";
    }
}

public class C2 : C1
{
    public override string GetName()
    {
        return "xiangshu";
    }
}

 C1 c1 = new C1();
 Console.WriteLine(c1.GetName());//输出“祥叔”

 C2 c2 = new C2();
 Console.WriteLine(c2.GetName());//输出“xiangshu”

 //重点看这里

 C1 c3 = new C2();
 Console.WriteLine(c3.GetName());//输出“xiangshu” 

#endregion

复制代码

 

覆盖
在子类中用 new 关键字修饰 定义的与父类中同名的方法,叫覆盖。
覆盖不会改变父类方法的功能。

看下面演示代码:

复制代码
#region 覆盖

public class C1
{
    public string GetName()
    {
        return "祥叔";
    }
}

public class C2 : C1
{
    public new string GetName()
    {
        return "xiangshu";
    }
}

C1 c1 = new C1();
Console.WriteLine(c1.GetName());//输出“祥叔”

C2 c2 = new C2();
Console.WriteLine(c2.GetName());//输出“xiangshu”

//重点看这里,和上面的重写作比较

C1 c3 = new C2();
Console.WriteLine(c3.GetName());//输出“祥叔” 

#endregion

复制代码

 

总结

1:不管是重写还是覆盖都不会影响父类自身的功能(废话,肯定的嘛,除非代码被改)。

2:当用子类创建父类的时候,如 C1 c3 = new C2(),重写会改变父类的功能,即调用子类的功能;而覆盖不会,仍然调用父类功能。

3:虚方法、实方法都可以被覆盖(new),抽象方法,接口 不可以。

4:抽象方法,接口,标记为virtual的方法可以被重写(override),实方法不可以。

5:重写使用的频率比较高,实现多态;覆盖用的频率比较低,用于对以前无法修改的类进行继承的时候。

父类引用指向子类对象(基类声明变量,子类实例化)注意三种情况

一)、基类是否有virtual,先扫描自己(基类),如果没有,调用自己(基类)的方法,当然所有继承它类的子类就不能有override方法:

    public class Person
    {
        public  void show()
        {
            Console.WriteLine("我是人");
        }
    }

    public class Student : Person
    {
        public  void show()
        {//override若存在就会报错
            Console.WriteLine("我是学生!");
        }
    }

    public class Teacher : Person

    {
        public void show()
        {
            Console.WriteLine("我是教师");
        }
    }

父类引用指向子类对象:

Person person = new Student();
person.show();

输出结果:

 

二)、基类有virtual,子类是否有override,若没有,还是调用自己(基类)的方法:

 

    public class Person
    {
        public virtual void show()

        {
            Console.WriteLine("我是人");
        }
    }

    public class Student : Person
    {
        public void show()
        {
            Console.WriteLine("我是学生!");
        }
    }

 

父类引用指向子类对象:

Person person = new Student();
person.show();

输出结果:

 

三)、基类含有virtual,子类有override,调用子类的方法:

 

    public class Person
    {
        public virtual void show()

        {
            Console.WriteLine("我是人");
        }
    }

    public class Student : Person
    {
        public override void show()
        {
            Console.WriteLine("我是学生!");
        }
    }

父类引用指向子类对象:

Person person = new Student();
person.show();

输出结果:

 

 

子类实例化子类

 扫描自己是否有方法,如果没有,找基类的方法,基类若没有,再往上基类找,一直往上面找,若找不到就报错:

    public class Person
    {
        public virtual void show()

        {
            Console.WriteLine("我是人");
        }
    }

    public class Student : Person
    {

    }

Student student = new Student();
student.show();

输出结果:

 

 

 

C#的抽象类和方法,重载,覆盖,隐藏

2008-03-06 16:38:07 / 个人分类:编程学习

第四例 C#的抽象类和方法,重载,覆盖,隐藏

 

using System;

namespace testClassApp
{
   /// <summary>
   /// Class1 的摘要说明。
   /// </summary>
   class Class1
   {
       /// <summary>
       /// 应用程序的主入口点。
       /// </summary>
       [STAThread]
       static void Main(string[] args)
       {
          //
          // TODO: 在此处添加代码以启动应用程序
          //

          double len = 2.5;
          double wid = 3.0;
          double rad = 4.1;
          Rectangle aRect = new Rectangle();
          aRect.length = len;
          aRect.width = wid;
          Circle aCirc = new Circle (rad);
          Console.WriteLine ("Area of Rect is:{0}",aRect.Area ());
          Console.WriteLine ("Area of Circ is:{0}",aCirc.Area ());
       }
   }

   abstract class Shape             //抽象基类,不可实例化
   
/* 1)声明一个抽象类使用abstract关键字
     * 2)只要包含抽象方法的类就是抽象类(哪怕只有一个),当一个抽象类中所有的方法都是抽象时,我们就可以定义成接口
     * 一个类可以包含一个或多个抽象方法
     * 3)抽象类中可以存在非抽象的方法(方法可以有具体的实现)
     * 4)抽象类不能被实例化
     * 5)实现抽象类用":",实现抽象方法用override关键字
     * 6)抽象类可以被抽象类所继承,结果仍是抽象类
     * 7)抽象方法被实现后,不能更改修饰符
    */
    {
       public const double pi=3.14;  //常量
       protected double x, y;        //私有,可继承变量
       
//构造函数
        /*
         1)对象最初对对象进行实例化的过程叫做构造阶段,这个过程就是由构造函数完成的,构造函数就是用于初始化数据的函数。
         2)所有的对象(类)都有一个默认的构造函数,没有参数,与类同名,但一个类可以包含几个带参数的构造函数
        称为非默认的构造函数。
         3)构造函数用new关键字来调用,例如:
         * 调用默认构造函数:类名类的实例名= new 类名();
         * 调用非默认构造函数:类名类的实例名= new 类名(参数);
         * 4)构造函数与字段,属性,方法一样,可以使公共或者私有的
         * 5)构造函数只是在对象被建立时调用,就是一句代码也不写或没有实现构造函数,那么这个类也会建立,
         * 这个函数只是说在对象在建立的时候给了一个给这个对象初始设置值的机会
         */
        public Shape()               //默认构造函数
       {
          x=y=0;
       }
       public Shape(double x,double y)  //带参数构造函数
       {
          this.x = x;
          this.y = y;
       }
       public abstract double Area();   //抽象方法,需重载
        /*
         * 1)声明一个抽象方法使用abstract关键字,抽象方法只包含方法定义,但没有具体实现的方法,需要其子类或者子类的子类来具体实现
         * 2)子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。也可以不实现抽象方法,留给后代实现,
         * 这时子类仍旧是一个抽象类,必须声明为abstract
         * 3)继承的抽象方法不可以被隐藏
         */

    }

   class Rectangle: Shape
   {
       public Rectangle():base(){}
       public Rectangle(double x, double y): base(x,y){}//使用基类构造函数
       
/*
         1) 隐式调用基类构造函数:如果没有明确指明base()( 即不使用base() ),子类会自动调用基类的默认构造器
         2) 显示调用:上面的就是显示调用,使用base(参数)
         */
        public override double Area()   //函数覆盖,子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。
            //也可以不实现抽象方法,留给后代实现,
       {
          return (x*y);
       }
       public double length   //属性:矩形长度
       {
          get
          {
             return x;
          }
          set
          {
             if (value>0){x = value;}
          }
       }
       public double width    //属性:矩形宽度
       {
          get
          {
             return y;
          }
          set
          {
             if (value>0){y = value;}
          }
       }

   }

   class Ellipse: Shape
   {
       public Ellipse(double x, double y):base(x,y){}//使用基类Shape的构造函数
       public override double Area() //函数覆盖
       {
          return pi*x*y;
       }
   }
   class Circle: Ellipse
   {
       public Circle(double r):base(r,0){}  //使用基类Ellipse的构造函数
       public override double Area() //函数覆盖
       {
          return pi*x*x;
       }
   }
       
   //隐藏:在子类中创建与父类中的方法具有相同签名(相同的方法名,相同的参数列表-参数类型和次序)的方法(可以带有"virtual"或"override"关键字)即可实现,但建议使用"new"关键字,以明确地隐藏。
          //只能使用"override"关键字来覆盖(override)父类中标记为"virtual"、"abstract"或"override"的方法,而子类中标记为override的方法,也必须是父类中标记为"virtual"、"abstract"或"override"的方法。
          //覆盖(override):必须使用override关键字,可以被覆盖的方法包括标记为abstract,virtual,和override的方法;
          //隐藏:使用new关键字,也可不使用关键字,可以被隐藏的方法包括一般方法,和标记为virtual"或"override"的方法;
          //重载(overload):不需要任何特殊的关键字
          //静态方法可以被隐藏或重载
    /*重载,覆盖,隐藏之间的区别
     重载(overload)用于同一类中的成员函数,其特征为:
     * 1)在同一类中
     * 2)相同的函数名
     * 3)参数不同(包括参数类型不同,或参数个数不同,或两者都不同,注意:和返回值没关系)
     * 4)和是否虚函数无关
     覆盖(override)是指派生类函数覆盖基类函数,其特征为:
     * 1)不同的范围(分别位于派生类与基类)
     * 2)相同的函数名称
     * 3)参数相同
     * 4)基类函数必须是虚函数
     隐藏(hide)是指派生类的函数屏蔽了与其同名的基类函数,其特征为:
     * 1)不同的范围(分别位于派生类与基类)
     * 2)相同的函数名
     (3)若参数不同,基类函数无virtual关键字,基类函数将会被隐藏。(因为派生类和基类不在同一范围,所以是隐藏而不是重载);
    ()若参数不同,基类函数有virtual关键字。基类函数将会被隐藏。(因为派生类和基类不在同一范围,所以是隐藏而不是重载;因为参数不同,所以是隐藏而不是覆盖);
    ()若参数相同,基类函数无virtual关键字。基类函数将会被隐藏。(因为基类函数不是虚函数,所以是隐藏而不是覆盖)。
    ()若参数相同,基类函数有virtual关键字。如果基类函数有多个重载版本,且派生类并没有重写所有的同名虚函数,当在派生类中调用函数时,基类中未被重写的虚函数将被隐藏。(当然,被重写的函数就是覆盖了)。
注意: 如果想在派生类中调用基类中的被隐藏的函数,可以在派生类中填写如下代码:using Base::Fun2
     */

}

目前C#100例的整理进度

目前C#100例的整理进度

C#接口的作用实例解析

2009-08-31 17:30 yuanhao 博客园 字号:T |
T
一键收藏,随时查看,分享好友!

谈到C#接口的作用是我们编程学习的初级障碍,那么如何很好的理解和学习C#接口的作用呢?本文向你详细介绍了C#接口的作用的相关内容。

AD:51CTO学院:IT精品课程在线看!

C#接口的作用是什么呢?首先我们来看看什么事实C#接口,C#接口是一个让很多初学C#者容易迷糊的东西,用起来好像很简单,定义接口,里面包含方法,但没有方法具体实现的代码,然后在继承该接口的类里面要实现接口的所有方法的代码,但没有真正认识到接口的作用的时候就觉得用接口是多此一举,当然你这样想那是绝对绝对错误的,比尔盖茨的微软请的员工都是比盖茨还聪明的人,他们的C#能添这样的多足吗?!关于接口的作用,网上有一位就真的深入浅出给我们做了很好理解的分析。

C#接口的作用解释实例:

  1. public interface IBark  
  2. {  
  3.     void Bark();  

再定义一个类,继承于IBark,并且必需实现其中的Bark()方法

  1. public class Dog:IBark  
  2. {  
  3.     public Dog()  
  4.     {}  
  5.     public void Bark()  
  6.     {  
  7.        Consol.write("汪汪");  
  8.      }  

然后,声明Dog的一个实例,并调用Bark()方法

  1. Dog 旺财=new Dog();  
  2. 旺财.Bark(); 

试想一样,若是想调用Bark()方法,只需要在Dog()中声明这样的一个方法不就行了吗,干什么还要用接口呢.因为接口中并没有Bark()具体实现.真的实现还是要在Dog()中.那么使用接口不是多此一举吗?

还有人是这样说的:从接口的定义方面来说,接口其实就是类和类之间的一种协定,一种约束.还拿上面的例子来说.所有继承了IBark接口的类中必需实现Bark()方法.那么从用户(使用类的用户)的角度来说,如果他知道了某个类是继承于IBark接口,那么他就可以放心大胆的调用Bark()方法,而不用管Bark()方法具体是如何实现的.比如,我们另外写了一个类.

  1. public class Cat:IBark  
  2. {  
  3.    public Cat()  
  4.    {}  
  5.    public void Bark()  
  6.    {  
  7.       Consol.write("喵喵");  
  8.    }  

当用户用到Cat类或是Dog类的时候,知道他们继承于IBark,那么不用管类里的具体实现,而就可以直接调用Bark()方法,因为这两个类中肯定有关于Bark()方法的具体实现.

如果我们从设计的角度来看.一个项目中用若干个类需要去编写,由于这些类比较复杂,工作量比较大,这样每个类就需要占用一个工作人员进行编写.比如A程序员去定Dog类,B程序员去写Cat类.这两个类本来没什么联系的,可是由于用户需要他们都实现一个关于"叫"的方法.这就要对他们进行一种约束.让他们都继承于IBark接口,目的是方便统一管理.另一个是方便调用.当然了,不使用接口一样可以达到目的.只不过这样的话,这种约束就不那么明显,如果这样类还有Duck类等等,比较多的时候难免有人会漏掉这样方法.所以说还是通过接口更可靠一些,约束力更强一些.

C#接口的作用以及相关的内容就向你介绍到这里,希望对你了解和学习C#接口的作用有所帮助。

抱歉!评论已关闭.