C# 关键字--virtual(转)

C# 关键字--virtual

一、

virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。虚拟成员的实现可由派生类中的重写成员更改,而非虚拟成员是无法由派生类进行重写的,这一点是与Java不同的。Java语言中,只要在派生类中定义了与父类具有相同签名的方法,那么父类的方法就被重写。C#语言中,必须使用virtual关键字进行修饰,否则在派生类中进行重写会导致编译器报错。

虚方法或者虚属性并不等同于抽象方法、抽象属性。抽象方法和抽象属性无法直接调用,必须通过派生类进行实现之后才能调用;而虚方法和虚属性是表示在派生类中有可能进行重写的,但是如果没有重写,那么将调用父类中的该虚方法和虚属性。调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。

默认情况下,方法是非虚拟的,不能重写非虚方法(除非使用new关键字)。virtual
修饰符不能与static、abstract、private 或
override
修饰符一起使用。除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。注意:
    ①在静态属性上使用 virtual 修饰符是错误的。
    ②通过包括使用 override
修饰符的属性声明,可在派生类中重写虚拟继承属性。

虚拟方法
   
若一个实例方法的声明中含有 virtual
修饰符,则称该方法为虚拟方法。若其中没有 virtual
修饰符,则称该方法为非虚拟方法。非虚拟方法的实现是不会变的:无论是在声明它的类的实例上调用该方法还是在派生类的实例上调用,实现都是相同的。与此相反,一个虚拟方法的实现可以由派生类取代。取代所继承的虚拟方法的实现的过程称为重写该方法。

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 ab = b;//这里a的类型是B类对象
           
A a = new A();
           
a.F();  //打印A.F
           
b.F();  //打印B.F
           
ab.F(); //打印A.F
           
a.G();  //打印B.G
           
b.G();  //打印B.G
           
ab.G(); //打印B.G
       }
   
}

注意:从a.F()与ab.G()返回的结果可以看出,利用new和override关键字对方法进行重写是有区别的。

  1. 基类对象调用基类对应的方法,不管是否是虚拟方法。
  2. 派生类对象分两种情况
    ①引用声明为派生类变量:调用派生类的方法
    ②引用声明为基类变量:
           
    ■如果利用override重写,那么调用派生类中的重写之后的方法。
           
    ■如果利用new重写,那么调用基类方法。

注意:上述原则对虚拟属性同样适用!

二、

class A
{
public virtual void Func() // 注意virtual,表明这是一个虚拟函数
{
Console.WriteLine("Func In A");
}
}
class B : A // 注意B是从A类继承,所以A是父类,B是子类
{
public override void Func() // 注意override ,表明重新实现了虚函数
{
Console.WriteLine("Func In B");
}
}
class C : B // 注意C是从B类继承,所以B是父类,C是子类
{
}
class D : A // 注意D是从A类继承,所以A是父类,D是子类
{
public new void Func() // 注意new ,表明覆盖父类里的同名类,而不是重新实现
{
Console.WriteLine("Func In D");
}
}
class Program
{
static void Main(string[] args)
{
A a; // 定义一个a这个A类的对象.这个A就是a的申明类
A b; // 定义一个b这个A类的对象.这个A就是b的申明类
A c; // 定义一个c这个A类的对象.这个A就是c的申明类
A d; // 定义一个d这个A类的对象.这个A就是d的申明类
a = new A(); // 实例化a对象,A是a的实例类
b = new B(); // 实例化b对象,B是b的实例类
c = new C(); // 实例化c对象,C是c的实例类
d = new D(); // 实例化d对象,D是d的实例类
a.Func(); // 执行a.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类A,就为本身 4.执行实例类A中的方法 5.输出结果 Func In A
b.Func(); // 执行b.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重载的 4.执行实例类B中的方法 5.输出结果 Func In B
c.Func(); // 执行c.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重载的 4.转去检查类C的父类B,有重载的 5.执行父类B中的Func方法 5.输出结果 Func In B
d.Func();
// 执行d.Func:1.先检查申明类A 2.检查到是虚拟方法
3.转去检查实例类D,无重载的(这个地方要注意了,虽然D里有实现Func(),但没有使用override关键字,所以不会被认为是重载)
4.转去检查类D的父类A,就为本身 5.执行父类A中的Func方法 5.输出结果 Func In A
D d1 = new D();
d1.Func(); // 执行D类里的Func(),输出结果 Func In D
Console.ReadLine();
}
}

时间: 2024-10-07 20:54:47

C# 关键字--virtual(转)的相关文章

浅谈C#中new、override、virtual关键字的区别

OO思想现在已经在软件开发项目中广泛应用,其中最重要的一个特性就是继承,最近偶简单的学习了下在设计模式中涉及到继承这个特性时,所需要用到的关键字,其中有一些关键点,特地整理出来. 一.New 在C#中,new这个关键字使用频率非常高,主要有3个功能: a)   作为运算符用来创建一个对象和调用构造函数. b)   作为修饰符. c)   用于在泛型声明中约束可能用作类型参数的参数的类型. 在本文中,只具体介绍new作为修饰符的作用,在用作修饰符时,new关键字可以在派生类中隐藏基类的方法,也就说

20151024_004_C#基础知识(C#中的访问修饰符,继承,new关键字,里氏转换,is 和 as,多态,序列化与反序列化)

1:C#中的访问修饰符 public: 公共成员,完全公开,没有访问限制. private: 私有的,只能在当前类的内部访问. protected: 受保护的,只能在当前类的内部以及该类的子类中访问. internal: 只能在当前项目中访问,在同一个项目中,internal和public的权限是一样的. protected internal: protected + internal权限. 1.1:能够修饰类的访问修饰符只有两个: public / internal 1.2:接口中的成员不允许

C++ Virtual详解

Virtual是C++ OO机制中很重要的一个关键字.只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖.当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数.这是面向对象中的多态性的体现.(关于虚拟机制是如何实现的,参见Inside t

[转]C++ Virtual详解

Virtual是C++ OO机制中很重要的一个关键字.只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在 Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖.当基类Base的指针point指向派生类Derived的对象 时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数.这是面向对象中的多态性的体现. (关于虚拟机制是如何实现的,参见Insid

Virtual 和 Abstract的区别

二者都是用来修饰基类的,通过覆盖基类的定义,让派生类重新定义. 相同点:如果用于修饰方法,必须声明为Public(公有的)或者Protected(受保护的),因为派生类是不能访问Private(私有)方法的. 不同点: Virtual:虚拟的,1基类中Virtual修饰的方法必须有实现,即便是只有一个大括号.2.派生类中Virtual可以被重写,也可以不被重写.在派生类中,要实现该修饰的方法的时候,  必须使用关键字Override(告诉编译器,需要重写虚方法),必须有实现.3.C#中如果要在派

Virtual应用在析构函数和构造函数调用中

1.在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数.例如: class B { virtual ~B(); - }; 该类中的析构函数就是一个虚析构函数. 如果一个基类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚析构函数,不管它是否使用了关键字virtual进行说明. 说明虚析构函数的目的在于在使用delete运算符删除一个对象时,能保析构函数被正确地执行.因为设置虚析构函数后,可以采用动态联编方式选择析构函数. 下面举一个用虚析构函数的例子. #inc

c#中的关键字

c#中的关键字 关键字是对编译器具有特殊意义的预定义保留标识符.它们不能在程序中用作标识符,除非它们有一个 @ 前缀.例如,@if 是有效的标识符,但 if 不是,因为 if 是关键字. 下面是列出的所有的关键字在 C# 程序的任何部分都是保留标识符: abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum

c++之虚函数virtual , overriding , overwrite

先来看下普通的继承: class Instrument{ public: void play() const{ cout<<"Instrument::play"<<endl; } }; class Wind : public Instrument{ public: void play() const{ cout<<"Wind::play"<<endl; } }; Instrument* instrumentObj =

C#基础知识(base、this、new、override、abstract、virtual、static)

前言 本文主要来讲解一下C#中,自己觉得掌握的不怎么样或者用的不多,不太熟悉的关键字,主要包括base.this.new.override.abstract.virtual以及针对static字段和static构造函数之间的执行问题. base关键字 base 关键字用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数.实例方法和实例属性访问器中: 调用基类上已被其他方法重写的方法. public class Father { public virtual void Say()