继承中的virtual,override,new,abstract

本文详细解析了 C# 中 virtual、override、new 和 abstract 的使用区别,通过具体示例阐述了如何实现继承与多态。文章强调了这些关键字在父类与子类之间的方法覆盖和隐藏的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承中的virtual,override,new,abstract

   写这个,只是想作个总结,刚刚看完继承章节中的这部分,乱乱的,理一下思路.
一般的继承就不再说了,现在主要说一下virtual,override,new,abstract的区别
和作用等.
   先说new.平时我们都是用他来声明一个对象,当然在struct和enum中也可以使
用他,我试过,虽然不是类,也不像对象,但是可以这样使用.这里的new是在子类中
要覆盖掉父类时使用new标识符.
  比如父类中有个方法:
  public void GetFullName()
  {}

  当子类继承父类后,想改变此方法,覆盖掉父类的方法就可以使用new
  public new void GetFullName()
  {}

  这么简单,费了这么多话.让大家失望了

  使用virtual和override的目的是能够让您能调用实际被赋值给的对象
所属类中的方法,而不是基类(父类)的方法这么说说的不清楚,看代码

using System;

class Person
{
        protected string firstName;
        protected string lastName;

        public Person()
        {
        }

        public Person(string fn,string ln)
        {
                firstName=fn;
                lastName=ln;
        }

        public virtual void GetFullName()
        {
                Console.WriteLine("{0} {1}",firstName,lastName);
        }
}

class Employee:Person
{
        public ushort hireYear;

        public Employee():base()
        {
        }

        public Employee(string fn,string ln,ushort hy):base(fn,ln)
        {
                hireYear=hy;
        }

        public override void GetFullName()
        //public new void GetFullName()
        {
                Console.WriteLine("Employee:{0} {1}",firstName,lastName);
        }
}

//A new class derived from Person...
class Contractor:Person
{
        public string company;

        public Contractor():base()
        {
        }

        public Contractor(string fn,string ln,string c):base(fn,ln)
        {
                company=c;
        }

        public override void GetFullName()
        //public new void GetFullName()
        {
                Console.WriteLine("Contractor:{0} {1}",firstName,lastName);
        }
}

class NameApp
{
        public static void Main()
        {
                Person Brad=new Person("Bradley","Jones");
                Person me=new Employee("Bradley","Jones",1983);
                Person Greg=new Contractor("Hill","Batfield","Data Diggers");

                Brad.GetFullName();
                me.GetFullName();
                Greg.GetFullName();
        }
}

当使用override时,显示的
Bradley Jones
Employee:Bradley Jones
Contractor:Hill Batfield

而使用new则不是,可以试试

因为父类对象调用的子类中的方法,请注意看Main中的声明对象代码
还有new单纯就是覆盖,仅仅就是覆盖调父类中的方法,而使用当前的方法
有没有virtual都是一样的,而且他也不允许父类对象调用子类中的方法.

使用override是允许父类声明的对象(当被赋值为子类时如:Father a=new Son())
可以使用子类声明的方法.

虽然基类的方法被声明为虚拟的(以便实现多态),但要根据赋值变量的数据类型来
调用相应的方法,还必须在派生类的方法中使用关键字override.可以强制派生类覆盖
基类的方法:将基类的方法声明为抽象(abstract)的.抽象方法没有方法体,由派生类提供.

using System;

class Person
{
        protected string firstName;
        protected string lastName;

        public Person()
        {
        }

        public Person(string fn,string ln)
        {
                firstName=fn;
                lastName=ln;
        }

        public abstract void GetFullName()
}

class Employee:Person
{
        public ushort hireYear;

        public Employee():base()
        {
        }

        public Employee(string fn,string ln,ushort hy):base(fn,ln)
        {
                hireYear=hy;
        }

        public override void GetFullName()
 //public new void GetFullName()
        {
                Console.WriteLine("Employee:{0} {1}",firstName,lastName);
        }
}

//A new class derived from Person...
class Contractor:Person
{
        public string company;

        public Contractor():base()
        {
        }

        public Contractor(string fn,string ln,string c):base(fn,ln)
        {
                company=c;
        }

        public override void GetFullName()
 //public override void GetFullName()
        {
                Console.WriteLine("Contractor:{0} {1}",firstName,lastName);
        }
}

class NameApp
{
        public static void Main()
        {
                //Person Brad=new Person("Bradley","Jones");
                Person me=new Employee("Bradley","Jones",1983);
                Person Greg=new Contractor("Hill","Batfield","Data Diggers");

                //Brad.GetFullName();
                me.GetFullName();
                Greg.GetFullName();
        }
}

对应于abstract声明的方法,我们使用的相应的标识符仍为override,如果使用new会报错.
这里给父类对象赋值为子类,但调用GetFullName方法的却是子类中的方法,因为父类中没有方法体.

   总结一下,new可以使用在有virtual或无virtual的时候,但不能用在abstract中.
override对应的是virtual和abastact.和new的主要区别在于,当出现
   Father a=new Sun();
   如上声明对象的情况时,使用new声明的方法使用的仍是父类方法,而override声明的方法使用的是子类中的方法.
   override 说明的是虚方法,new则不是。
   new 为了让人清楚知道覆盖了父类方法.
   override 才有实际作用,后期联编

 ------------------------------------------------------------------------------------------------------------------------------------------------

 

abstract & virtual & override & new

abstract
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。

在类声明中使用 abstract 修饰符以指示类只能是其他类的基类。

抽象类具有以下特性:
·抽象类不能实例化
·抽象类可以包含抽象方法和抽象访问器。
·不能用 sealed 修饰符修改抽象类,这意味着该类不能被继承。
·从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
·在方法或属性声明中使用 abstract 修饰符以指示此方法或属性不包含实现。

抽象方法具有以下特性:
·抽象方法是隐式的 virtual 方法。
·只允许在抽象类中使用抽象方法声明。
·因为抽象方法声明不提供实实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。例如: public abstract void MyMethod();
·实现由 overriding 方法提供,它是非抽象类的成员。
·在抽象方法声明中使用 static 或 virtual 修饰符是错误的。

除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
·在静态属性上使用 abstract 修饰符是错误的。
·在派生类中,通过包括使用 override 修饰符的属性声明可以重写抽象的继承属性。

virtual
virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。

调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。

默认情况下,方法是非虚拟的。不能重写非虚方法。

不能将 virtual 修饰符与以下修饰符一起使用:
static   abstract   override

除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。
·在静态属性上使用 virtual 修饰符是错误的。
·通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。

override(覆盖上面两种关键字修饰方法)
使用 override 修饰符来修改方法、属性、索引器或事件。重写方法提供从基类继承的成员的新实现。由重写声明重写的方法称为重写基方法。重写基方法必须与重写方法具有相同的签名。

不能重写非虚方法或静态方法。重写基方法必须是虚拟的、抽象的或重写的。

重写声明不能更改虚方法的可访问性。重写方法和虚方法必须具有相同的访问级修饰符。

不能使用下列修饰符修改重写方法:
new   static    virtual   abstract

重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且重写属性必须是虚拟的、抽象的或重写的。

using  System;

namespace  VitualMethod
{
    
class BeiseClass
    
{
        
public void RealMethod()
        
{
            Console.WriteLine(
@"The ""RealMethod"" method of ""BeiseClass"" class!"); 
        }


        
public virtual void ViutualMethod() 
        
{
            Console.WriteLine(
@"The ""ViutualMethod"" method of ""BeiseClass""class!"); 
        }

    }


    
class NewAndOverride: BeiseClass
    
{
        
/// <summary>
        
/// “new”用于隐藏基类成员的继承成员,是重写方法的另一种办法;
        
/// 在同一成员上同时使用 new 和 override 是错误的;
        
/// “override”只是隐藏了虚拟方法。
        
/// </summary>

        new public void RealMethod() 
        
{
            Console.WriteLine(
@"The ""RealMethod"" method of ""NewAndOverride"" class!"); 
        }


        
public override void ViutualMethod() 
        
{
            Console.WriteLine(
@"The ""ViutualMethod"" method of ""NewAndOverride""class!"); 
        }

    }


    
class Tester
    
{
        
/// <summary>
        
/// 运行结果:
        
/// The "RealMethod" method of "BeiseClass" class!
        
/// The "RealMethod" method of "NewAndOverride" class!
        
/// The "ViutualMethod" method of "BeiseClass"class!
        
/// The "ViutualMethod" method of "NewAndOverride"class!
        
/// 
        
/// The "RealMethod" method of "BeiseClass" class!
        
/// The "ViutualMethod" method of "NewAndOverride"class!
        
/// </summary>

        static void Main() 
        
{
            BeiseClass beiseClass 
= new BeiseClass();
            NewAndOverride newAndOverride 
= new NewAndOverride();
        
            beiseClass.RealMethod();
            newAndOverride.RealMethod();
        

            beiseClass.ViutualMethod();
            newAndOverride.ViutualMethod();

            Console.WriteLine();

            
//
            
// 注意:可以看到隐藏方法仍然存在,而被覆盖的方法已经不存在了;
            
//
            beiseClass = newAndOverride;
            
            beiseClass.RealMethod();
            beiseClass.ViutualMethod();

        }

    }

}


new
使用 new 修饰符显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。

类成员声明中可以使用与一个被继承的成员相同的名称或签名来声明一个成员。发生这种情况时,就称该派生类成员隐藏了基类成员。隐藏一个继承的成员不算是错误,但这确实会导致编译器发出警告。若要取消此警告,派生类成员的声明中可以包含一个 new 修饰符,表示派生成员是有意隐藏基成员的。

 

using  System;

namespace  TheNewKeyword
{

    
class NewTestClassBase
    
{
        
public void PrintNewKeyword()
        
{
            Console.WriteLine(
@"This is base class!");
        }

    }


    
class NewTestClass : NewTestClassBase
    
{
        
/// <summary>
        
/// 如果这样写:
        
/// override public void PrintNewKeyword()
        
/// 
        
/// 将产生编译错误:
        
/// “TheNewKeyword.NewTestClass.PrintNewKeyword()” : 
        
/// 无法重写继承成员“TheNewKeyword.NewTestClassBase.PrintNewKeyword()”,
        
/// 因为它未标记为 virtual、abstract 或 override。
        
/// </summary>

        new public void PrintNewKeyword()
        
{
            Console.WriteLine(
@"This is ""new"" keyword!");
        }

    }


    
    
/// <summary>
    
/// TheNewKeyword 测试“new”关键字。
    
/// </summary>

    class TheNewKeyword
    
{
        
/// <summary>
        
/// 运行结果:
        
/// This is base class!
        
/// This is "new" keyword! 
        
/// </summary
        static void Main()

        {
            
//
            
// TODO: 在此处添加代码以启动应用程序
            
//
            NewTestClassBase newTestClassBase = new NewTestClassBase();
            NewTestClass newTestClass 
= new NewTestClass();

            newTestClassBase.PrintNewKeyword();
            newTestClass.PrintNewKeyword();
        }

    }

}

 

-----------------------------------------------------------------------------------------------------------------------------------

   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()   //因为基类已经实现了Work方法,而在子类中又实现了Work方法,所以                                 //编译器会报警,在前面加上 new(隐藏基类方法),是将警报关闭。
        {
            base.Work();   //调节基类Popele的方法。显示“开始工作”
            //MessageBox.Show("管理员开始工作罗!");
        }

        public override void GetOffWork()      //覆盖基类的方法
        {
            MessageBox.Show("管理员下班啦");
        }
    }

    public class Employee():People
    {
       public Employee()
       {}

        new public void GetOffWork()      //virtual方法仍然可以 new
        {
            MessageBox.Show("职员下班啦!");
        }

    }

以上应该应该几点:
1、如果父类方法没有加virtual关键字,即不是一个虚方法,则在子类中只能隐藏基类方法,而不能覆盖。
2、如果父类方法加了virtual关键字,即它是一个虚方法,在子类中一样可以隐藏。
3、如果子类实现了父类相同的方法(相同的方法名称及签名),而没有new,在编译时会报警,但编译仍然能够通过!
3、调用父类方法:base.方法名()
4、abstract类是一个抽象类,不能被实例化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值