C#中的virtual和abstract

问题来源

virtual是实现C++多态的关键性条件:C++使用关键字virtual来修饰类中的方法,被修饰的方法可以在子类中重写,如此便覆盖基类方法,以实现相同的行为却不同的功能;多继承情况下的基类析构函数通常声明为virtual(虚方法),这样做的好处是:确保正确的析构顺序——基类对象的析构晚于子类对象。除此之外,如果基类中至少有一个函数被声明为纯虚函数(virtual void func()= 0;),那么这个基类为抽象基类,如此它便不能实例对象,并且必须在其派生类中对纯虚函数进行实现,而基类只能声明而不能实现,这类似于C#和JAVA语言中的接口interface。我们知道C#是在C++的基础之上删繁留简后形成的一门语言,它保留了C++很多特性,C#中virtual、abstract和interface这三个关键字经常迷惑初学者,它们有很多相似的地方,也有很多不同的地方。

分析

——virtual关键字

虚方法在哪里声明,又在哪里实现?它在基类中的作用有两种情况——1. 在我看来,基类中定义的虚方法(虚方法就是virtual修饰的方法)除了辅助实现多态特性,其实它和普通函数没什么区别。基类声明或基类定义(即实现)的虚方法,其派生类可以重写也可不重写;如果派生类不重写基类虚方法,那么派生类实例访问的虚方法是基类中定义的方法。。。。2. 在基类中定义了虚方法,并且在派生类中使用override重写了该方法(C++中使用virtual关键字表示要重写虚方法),那么派生类的实例调用中,该虚方法使用的是派生类中重写的方法。

——abstract关键字

抽象方法在哪里声明,又在哪里实现?C++有抽象的概念,但是没提供abstract关键字,C++使用纯虚函数来指明基类为抽象类,而C#显示使用abstract关键字来指明基类为抽象类。这两种语言中抽象类的特性是一致的:抽象类不能有实例,抽象类中的抽象方法(C#)和纯虚函数(C++)不能在基类中直接实现,必须在派生类中实现。简单粗暴的讲:C++中基类必须提供至少一个纯虚函数才可称为抽象基类,基类中不可实现它,必须是在子类中实现;C#中abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现。抽象类和C#中的接口interface有着很重要的异同点,这里不再赘述。

代码实例

using System;
using System.Data.SqlClient;

namespace Test
{
    public abstract class LogAbstract
    {
        public abstract void WriteLog(string Title, string Act, string Remark, int LogTypeId, int UserId);
    
        // 下面代码说明virtual和abstract的简单区别
        //public abstract void WriteLog(string str) { } // ERROR!-->无法声明主体,应为他被标记为abstract
        //public virtual void WriteLog(int i);// 如果不在子类中实现,则ERROR!--->必须声明主体,因为它未被标记为abstract、extern或particle
        virtual void WriteLog(int i);// OK--->基类声明子类实现; 或者直接在基类中实现,若子类再实现则是重写该方法
    }

    public class LogDerived : LogAbstract
    {
        
        // 向数据库表中写入日志
        public override void WriteLog(string Title, string Act, string Remark, int LogTypeId, int UserId)
        {
            // 与数据库连接的字符串
            string connStr = "server=localhost; uid=sa; pwd=123; database=db_PDRO";
            // sql语句
            string sql = "INSERT INTO LogTable (LogTitle, LogAction, LogActionRemark, LogTypeId, UserId) VALUES('" + Title + "', '" + Act + "', '" + Remark + "', '" + LogTypeId + "', '" + UserId + "')";

            using (SqlConnection conn = new SqlConnection(connStr))
            {
                conn.Open(); // 打开表
                SqlCommand comm = new SqlCommand(); // 创建SqlCommand对象
                comm.Connection = conn; // 设置comm要使用的SqlConnection对象
                comm.CommandText = sql; // 设置要执行的sql语句

                try
                {
                    comm.ExecuteNonQuery();
                }
                catch (SqlException e) {
                    throw e;
                }
            }
        }

        public override void WriteLog(int i) { }
    }

    class Program
    {
        static void Main(string[] args)
        {
            LogDerived log = new LogDerived();
            log.WriteLog("testLog1", "test", "log", 1, 1);
            log.WriteLog("testLog2", "test", "log", 1, 2);

            Console.Write("hello world!");
            Console.ReadLine();
        }
    }
}

写入数据到数据库中,如下图所示:


结语

这篇博客总结性的对virtual和abstract啰啰嗦嗦了好多,这都是它们太具有迷惑性。但希望能从这些啰嗦的文字中提取出主要信息,下面是对它们的简单粗暴的总结,看着下面的条目,请用脑袋思考下,看看自己是不是掌握了它们的特性。

1. virtual方法在基类中可以实现(若未实现,子类必须为其实现),abstract方法在基类中不可实现;而在派生类中,virtual方法可重写可不重写,abstract方法必须重写。

2. 抽象类不可创建实例,只能被继承,由派生类来实例化。

3. C#中有函数被声明为abstract,那么必须显式使用用abstract修饰类名。

4. C#中派生类重写基类的virtual或abstract方法,记得使用override修饰;C++中派生类重写基类的virtual方法,使用virtual修饰。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值