扩展或修改继承的方法、属性、索引器或事件的 abstract 或 virtual 实现需要 override 修饰符。

在以下示例中,“Lei正方形”类必须提供 GetArea 的重写实现,因为 GetArea 继承自抽象 Lei封闭形状 类:

static void Main(string[] args)
    {
        Lei正方形 zf4 = new ( 4 );
        Console . WriteLine( zf4 . ToString ( ) );
        Lei圆 yuan4 = new ( 4 );
        Console . WriteLine ( yuan4 . ToString ( ) );
    }

public abstract class Lei封闭形状
    {
        public abstract double _面积 ( );
        public abstract double _周长 ( );
    }

public class Lei正方形 : Lei封闭形状
    {
    private double _边长;
        
    public Lei正方形 ( double 边长 ) => _边长 = 边长;
        
    public override double _面积 ( )
        {
            return _边长 * _边长;
        }

    public override double _周长 ( )
        {
            return _边长 * 4;
        }

    public override string ToString ( )
        {
            return $"边长为:{_边长} 的正方形周长:{_周长 ( )};面积:{_面积 ( )}";
        }
    }

public class Lei圆 : Lei封闭形状
    {
        private double _半径;

        public Lei圆 ( double 半径 ) => _半径 = 半径;

        public override double _周长 ( )
            {
                return Math . Tau * _半径;
            }

        public override double _面积 ( )
            {
                return Math . PI * _半径 * _半径;
            }

        public override string ToString ( )
            {
                return $"半径为:{_半径} 的圆周长:{_周长 ( )};面积:{_面积 ( )}";
            }

上例中,“Lei正方形”和“Lei圆”均从“Lei封闭形状”中继承了“_周长”和“_面积”方法,并(必须)提供了新的实现。通过 override 声明重写的方法称为重写基方法。override 方法必须具有与重写基方法相同的签名。override 方法支持协变返回类型。具体而言,override 方法的返回类型可从相应基方法的返回类型派生。

不能重写非虚方法或 static 方法。重写基方法必须是 virtual、abstract 或 override。

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

不能使用 new、static 或 virtual 修饰符修改 override 方法。

重写属性声明必须指定与继承的属性完全相同的访问修饰符、类型和名称。只读重写属性支持协变返回类型。重写属性必须为 virtual、abstract 或 override。

人和家人

下面示例描述了基类“Lei人”和派生类“Lei家人”。

/// <summary>
/// 人的基类以及 new 过程,只描述了姓名、性别、生日和一个未实现的“昵称”
/// </summary>
/// <param name="姓名">此人姓名</param>
/// <param name="性别">此人性别</param>
public abstract class Lei人 ( string 姓名 , bool 性别 )
    {
    /// <summary>
    /// 允许某些人不知道姓名
    /// </summary>
    public string? 姓名
        {
            get; set;
        } = 姓名;

    /// <summary>
    /// 根据性别的 bool 返回“男”或“女”
    /// </summary>
    public bool _XingBie = 性别;
    public string 性别
        {
            get
                {
                if ( _XingBie )
                    return "男";
                return "女";
                }
        }

    private DateTime _ShRi;
    public DateTime 生日
        {
            get { return _ShRi; }
            set { _ShRi = value; }
        }

    /// <summary>
    /// 根据生日与当前时间的差距返回活了多少天
    /// </summary>
    public int 日龄
        {
            get => (DateTime . Now - _ShRi) . Days;
        }

    /// <summary>
    /// 必须重写的“昵称”属性
    /// </summary>
    public abstract string 昵称
        {
            get; set;
        }

    /// <summary>
    /// 重写的 ToString 方法
    /// </summary>
    /// <returns>“人”的字符串表示形式(姓名和性别)</returns>
    public override string ToString ( )
        {
            return $"{姓名},{性别}";
        }
    }

/// <summary>
/// 可以具体化的“家人”类,继承自“人”类
/// </summary>
public class Lei家人 : Lei人
    {
        private string? _NiCh;

        /// <summary>
        /// 重写的“人”类的“昵称”属性
        /// </summary>
        public override string 昵称
            {
                get
                    {
                        if ( _NiCh is null | _NiCh . Trim ( ) == string . Empty )
                            return "无";
                        return _NiCh;
                    }
                set => _NiCh = value;
            }

        /// <summary>
        /// 具有“昵称”的“家人”new 过程
        /// </summary>
        /// <param name="姓名">家人的姓名</param>
        /// <param name="性别">家人的性别</param>
        /// <param name="生日">家人的生日</param>
        /// <param name="昵称">家人的昵称</param>
        public Lei家人 ( string 姓名 , bool 性别 , DateTime 生日 , string 昵称 ) : base ( 姓名 , 性别 )
            {
                this . 生日 = 生日;
                this . 昵称 = 昵称;
            }

        /// <summary>
        /// 没有“昵称”属性的“家人”new 过程
        /// </summary>
        /// <param name="姓名">家人的姓名</param>
        /// <param name="性别">家人的性别</param>
        /// <param name="生日">家人的生日</param>
        public Lei家人 ( string 姓名 , bool 性别 , DateTime 生日 ) : base ( 姓名 , 性别 )
            {
                this . 生日 = 生日;
                this . 昵称 = "";
            }

        /// <summary>
        /// 重写的 ToString,返回“家人”的字符串表示形式
        /// </summary>
        /// <returns>家人的详细内容(姓名、性别、昵称(可无)、日龄)</returns>
        public override string ToString ( )
            {
            return $"{base . ToString ( )};昵称:{this . 昵称},日龄:{this . 日龄}";
            }
        }

    static void Main(string[] args)
        {
            Lei家人 LP = new ( "白芙蓉" , false , new DateTime ( 2003 , 4 , 5 ) , "死老婆" );
            Lei家人 NvEr = new ( "蓝玫瑰" , false , new DateTime ( 2023 , 11 , 19 ) );
            Lei家人 ErZi = new ( "白牡丹" , true , new DateTime ( 2020 , 12 , 31 ) );
            Console . WriteLine ( LP . ToString ( ) );
            Console . WriteLine ( ErZi . ToString ( ) );
            Console . WriteLine ( NvEr . ToString ( ) );   
        }

上例中“Lei家人”的 ToString 是可以不重写的,这样“Lei家人”的对象的 ToString 方法直接使用“Lei人”的。“Lei家人”必须实现继承自“Lei人”的“昵称”属性,因为该属性被明确为“抽象的”(abstract)。

由于“Lei家人”的 new 过程继承自“Lei人”的 new 过程,所以关于“姓名”和“性别”的赋值直接使用“Lei人”的 new 过程。


兔子码农
4 声望1 粉丝

一个酒晕子