using System;

namespace PersonApp
{
    // Person 类定义
    public class Person
    {
        // 数据成员
        private string name;
        private string gender;
        private int yearOfBirth;

        // 属性
        public string MyName
        {
            get { return name; }
            set { name = value; }
        }

        public string MyGender
        {
            get { return gender; }
            set { gender = value; }
        }

        public int MyYearOfBirth
        {
            get { return yearOfBirth; }
            set { yearOfBirth = value; }
        }

        // 只读属性,计算年龄
        public int Age
        {
            get
            {
                int currentYear = DateTime.Now.Year;
                return currentYear - yearOfBirth;
            }
        }

        // 构造函数,初始化数据成员
        public Person(string name, string gender, int yearOfBirth)
        {
            this.name = name;
            this.gender = gender;
            this.yearOfBirth = yearOfBirth;
        }

        // 方法:格式化输出姓名、称谓和年龄
        public virtual void Print()
        {
            string title = (gender.ToLower() == "男") ? "先生" : "女士";
            Console.WriteLine($"您好, {name}, {title}! 您今年{Age}岁。");
        }

    }
    public class Teacher : Person
    {
        // 数据成员
        private string tId;       // 工号
        private int tStartYear;   // 从教年份

        // 属性
        public string MyTId
        {
            get { return tId; }
            set { tId = value; }
        }

        public int MyTStartYear
        {
            get { return tStartYear; }
            set { tStartYear = value; }
        }

        // 计算从教年限的属性
        public int TeachingYears
        {
            get
            {
                int currentYear = DateTime.Now.Year;
                return currentYear - tStartYear;  // 计算从教年限
            }
        }

        // 构造函数
        public Teacher(string name, string gender, int yearOfBirth, string tId, int tStartYear)
            : base(name, gender, yearOfBirth) // 调用基类构造函数
        {
            this.tId = tId;
            this.tStartYear = tStartYear;
        }

        // 重载 Print 方法
        public override void Print()
        {
            base.Print();  // 调用基类的Print方法输出基本信息
            Console.WriteLine($"您已有{TeachingYears}年教龄,教师工号为:{tId}。");
        }
    }

    // 主程序
    class Program
    {
        static void Main(string[] args)
        {
            // 获取用户输入
            Console.WriteLine("请输入姓名:");
            string name = Console.ReadLine();

            Console.WriteLine("请输入性别(男或女):");
            string gender = Console.ReadLine();

            Console.WriteLine("请输入出生年份: ");
            int yearOfBirth;

            while (!int.TryParse(Console.ReadLine(), out yearOfBirth) || yearOfBirth <= 0)
            {
                Console.WriteLine("请输入有效的出生年份:");
            }                     

            // 创建 Teacher 对象(可以根据需要输入教工号和从教年份)
            Console.WriteLine("请输入教师工号:");
            string tId = Console.ReadLine();

            Console.WriteLine("请输入从教年份:");
            int tStartYear;

            while (!int.TryParse(Console.ReadLine(), out tStartYear) || tStartYear <= 0)
            {
                Console.WriteLine("请输入有效的从教年份:");
            }

            Teacher teacher = new Teacher(name, gender, yearOfBirth, tId, tStartYear);

            // 打印输出教师信息
            Console.WriteLine("【教师信息】");
            teacher.Print();

            // 等待用户按任意键退出程序
            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();  // 等待用户按任意键
        }
    }
}

在 C# 中,虚方法virtual)和抽象方法abstract)都是用于在基类中定义方法的特殊类型,它们允许在派生类中重写这些方法,但它们在用法和行为上有一些重要区别:

1. 虚方法(virtual

  • 定义: 在基类中声明的方法可以被派生类重写(override)。虚方法具有一个实现,但派生类可以选择覆盖它。

  • 行为: 虚方法有默认的实现。派生类可以选择是否重写这个方法。如果派生类没有重写该方法,那么基类的实现就会被调用。

  • 关键字: 使用 virtual 关键字来标记该方法为虚方法。

  • 示例:

    class BaseClass
    {
        public virtual void Display()
        {
            Console.WriteLine("Base class display.");
        }
    }
    
    class DerivedClass : BaseClass
    {
        public override void Display()
        {
            Console.WriteLine("Derived class display.");
        }
    }
    
    // 使用虚方法
    BaseClass obj = new DerivedClass();
    obj.Display();  // 输出: Derived class display.
    
  • 特点:

    • 可以有一个默认实现。
    • 可以被派生类覆盖(override)。
    • 如果派生类没有重写该方法,基类的实现会被调用。

2. 抽象方法(abstract

  • 定义: 抽象方法是没有实现的方法,它只是一个声明,表示必须在派生类中实现具体的逻辑。抽象方法只能在抽象类中声明。

  • 行为: 抽象方法没有任何实现,派生类必须提供具体的实现。如果派生类没有重写该方法,编译时会报错。

  • 关键字: 使用 abstract 关键字来标记该方法为抽象方法。

  • 示例:

    abstract class BaseClass
    {
        public abstract void Display();  // 抽象方法,没有实现
    }
    
    class DerivedClass : BaseClass
    {
        public override void Display()
        {
            Console.WriteLine("Derived class display.");
        }
    }
    
    // 使用抽象方法
    BaseClass obj = new DerivedClass();
    obj.Display();  // 输出: Derived class display.
    
  • 特点:

    • 没有方法体,只有声明。
    • 必须在派生类中提供实现。
    • 抽象方法只能在抽象类中声明,抽象类不能直接实例化。
    • 如果派生类没有实现抽象方法,编译器会报错。

总结:虚方法 vs 抽象方法

特性 虚方法 (virtual) 抽象方法 (abstract)
实现 可以有实现,派生类可以选择覆盖它 没有实现,派生类必须提供实现
类要求 可以在普通类中声明 必须在抽象类中声明
派生类要求 派生类可以选择覆盖(override 派生类必须覆盖(override),否则会报错
是否可以实例化 可以实例化基类(如果没有抽象成员) 不能实例化抽象类

使用场景:

  • 虚方法: 适用于基类希望提供默认实现,但又允许派生类根据需要重写该实现的情况。
  • 抽象方法: 适用于基类定义了一个协议,要求所有派生类必须提供具体实现的场景。

简而言之,虚方法提供默认实现,而抽象方法仅仅提供方法签名,要求派生类必须实现。

posted on 2024-11-05 20:58  zzzxxyy  阅读(18)  评论(0)    收藏  举报