virtual 用于修饰方法、事件、属性和索引器,指示该成员可以被派生类继承或重写。

internal class Program
    {
        static void Main(string[] args)
        {
            LeiP p = new ( );
            Console . WriteLine ( $"继承的方法:{p . FF ( )}" );
        }
    }

class LeiJi
    {
        public virtual int FF ( )
            {
                return 1 + 1;
            }
    }

class LeiP : LeiJi
    {
    }

上例中的类 LeiP 继承自 LeiJi,由于 LeiP 是空的(没有重写 FF),因此当声明 LeiP 对象 p 后,可以使用继承自 LeiJi 的方法 FF,输出:
继承的方法:2

继承的类,也可以重写基类的 virtual 成员,以提供新的实现:

internal class Program
    {
        static void Main(string[] args)
            {
                LeiP p = new ( );
                Console . WriteLine ( $"重写的方法:{p . FF ( )}" );
           }
    }

class LeiJi
    {
        public virtual int FF ( )
            {
                return 1 + 1;
            }
    }

class LeiP : LeiJi
    {
        public override int FF ( )
            {
                return 1 + 2;
            }
    }

上例中的类 LeiP 继承自 LeiJi,由于 LeiP 重写(override)了 FF,因此当声明 LeiP 对象 p 后,并非使用继承自 LeiJi 的方法 FF,而是输出:
重写的方法:3

virtual 成员既可以被派生类中的替代成员(override)更改,也可以直接继承。

注解

当调用 virtual 方法时,将检查对象的运行时类型是否有重写成员。如果没有派生类重写成员,则调用其基类中的重写成员,该成员可能是顶级基类的原始成员。

internal class Program
    {
        static void Main(string[] args)
            {
                LeiPs ps = new ( );
                Console . WriteLine ( $"重写的方法:{ps . FF ( )}" );
            }
    }

class LeiJi
    {
        public virtual int FF ( )
            {
                return 1 + 1;
            }
    }

class LeiP : LeiJi
    {
        public override int FF ( )
            {
                return 1 + 2;
            }
    }

class LeiPs : LeiP
    {
    }

上例中的 LeiPs 继承自 LeiP,并没有重写 FF,因此对象 ps 的 FF 方法是继承其基类 LeiP 的 FF,返回 3;倘若 LeiP 也没有重写 FF,则会继承 LeiJi 的 FF,返回 2。

缺省情况下,方法是非虚的。不能重写非虚方法。

下面的例子展示了一个虚拟属性:

class LeiJi
    {
        // 虚拟自动实现属性。重写只有在实现 get 和 set 访问器时才能提供专门的行为
        public virtual required string _名字
            {
                get; set;
            }

        // 带背域的普通 virtual 属性
        private int _数;
        public virtual int 数
            {
                get
                    {
                        return _数;
                    }
                set
                    {
                        _数 = value;
                    }
    }

class LeiP : LeiJi
    {
        private string? _Name;
        // 用普通属性覆盖自动实现的属性,以提供专门的访问器行为
        public override required string _名字
            {
                get
                        {
                            if ( _Name != null )
                                 return _Name;
                            else
                                return "未知";
                        }
                set
                    {
                        if ( ! string.IsNullOrEmpty( value ) )
                            {
                                _Name = value;
                            }
                        else
                            {
                                _Name = "未知";
                            }
            }
        }
    }

除声明和调用语法不同外,虚拟属性的行为与虚拟方法相似。

通过包括使用 override 修饰符的属性声明,可在派生类中替代虚拟继承属性。

示例

在该示例中,Lei形状 类包含 x、y 两个坐标和 面积 ( ) 虚拟方法。不同的形状类(如 Lei圆、Lei圆柱 和 Lei球)继承 Lei形状 类,并为每个图形计算表面积。每个派生类都有各自的 面积 ( ) 替代实现。

请注意,继承的类 Lei圆、Lei圆柱 和 Lei球 均使用初始化基类的构造函数。

下面的程序根据与 面积 ( ) 方法相关联的对象,通过调用 面积 ( ) 方法的适当实现,计算并显示每个图形的适当面积。

{
    static void Main ( string [ ] args )
        {
            double bj = 1.25 , g = 6.98;
            Lei形状 y = new Lei圆 ( bj );
            Console . WriteLine ( $"圆的面积:{ y . 面积 ( ):F2}" );
            Lei形状 yz = new Lei圆柱 ( bj , g );
            Console . WriteLine ( $"圆柱的表面积:{yz . 面积 ( ):F2}" );
            Lei形状 q = new Lei球 ( bj );
            Console . WriteLine ( $"球的表面积:{q . 面积 ( ):F2}" );
        }
    }

public class Lei形状
    {
        protected double _x , _y ;

        public Lei形状 ( )
            {

            }

        public Lei形状 ( double x , double y )
            {
                _x = x;
                _y = y;
            }

        public virtual double 面积 ( )
            {
                return _x * _y;
            }
        }

public class Lei球 ( double 半径 ) : Lei形状 ( 半径 , 0 )
    {
        public override double 面积 ( )
            {
                return 4 * Pi * Pow (_x , 2 );
            }
    }

public class Lei圆 ( double 半径 ) : Lei形状( 半径 , 0 )
    {
        public override double 面积 ( )
            {
                return Pi * Pow ( _x , 2 );
            }
    }

public class Lei圆柱 ( double 底面半径 , double 高 ) : Lei形状 ( 底面半径 , 高 )
    {
        public override double 面积 ( )
            {
                return Tau * Pow ( _x , 2 ) + Tau * _x * _y;
            }
    }

兔子码农
4 声望1 粉丝

一个酒晕子


« 上一篇
C# 的 using
下一篇 »
C# 的 async