热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

大家帮忙解释一下,虚函数(Virtual),抽象函数(abstract)和接口的区别。

大家好,小弟正在学习C#,现在学的是蒙蒙呼呼的,觉得:虚函数(Virtual),抽象函数(abstract)和接口他们不都是只提供函数名称,然后再类中去实现代码吗?为什么要有这么多呢?请大家帮忙分
大家好,小弟正在学习C#,现在学的是蒙蒙呼呼的,觉得:虚函数(Virtual),抽象函数(abstract)和接口他们不都是只提供函数名称,然后再类中去实现代码吗?为什么要有这么多呢?
请大家帮忙分析它们之间的不同,最好有个例子,或者是能说明白,这三个东西分别在什么时候用。

31 个解决方案

#1


sf自己坐,我在C#怎么也有五个星?没在这儿回答过问题啊。
唉!惭愧啊!

#2


1.虚函数(Virtual),可以写方法的实现,不一定要被继承。抽象函数(abstract)不能写方法的实现,必须被继承

#3


接口与纯抽象函数类似。它只能包含抽象方法,而不能包含任何实现方法,不能创建接口的实例。

#4


虛函數:由virtual聲明,它允許在派生類中被重寫,要重寫方法,必須先聲名為virtual
public class myclass


{
public virtual int myint()
{
函數体;
}
}
class myclass1:myclass
{
public override int myint()
{
函數体1;
}
}

抽象類、抽象函數:由abstract聲明,在抽象類中可以定義抽象方法,抽象方法基本沒有執行代碼,派生類必須重寫它,提供其執行代碼
public abstract class myclass
{
public abstract int myint();
}
public class myclass1:myclass
{
public override int myint()
{
函數体;
}
}

接口類:由interface聲明,是特殊的抽象類,是方法、屬性、事件和索引符的組合,沒有字段,其成員無執行方式,無構造函數,不允許進行運算符重載,接口和它的成員沒有任何訪問修飾符,它總是公共的,不能聲明為虛擬或靜態,繼承自接口的派生類必須實現接口中的所有方法
interface Imyinterface
{
void myfunction();
string name
{
get;
set;
}
}
class myclass:Imyinterface
{
void myfunction()
{
函數体;
}
string name
{
get
{
return name;
}
set
{
name=value;
}
}
}

#5


學習了

#6


http://www.0531s.com/www/9/2008-01/76841.html
看看有沒有能幫到你的

#7


虛函式其實和抽象函式沒有什麽大的區別,只是虛函式可以像普通函式一樣可以在裏面寫程式碼.
編譯器會在編譯的時候適當的調用虛函式的複寫.
還有 要是你寫一個抽象函式,那麽這個抽象函式所在的類就必須是抽象類,抽象類沒有實體.

接口其實就是一個"樣板",那裏面寫著如果按照我這個"樣板"做自己的類,那麽你那個類裏就必須有什麽什麽函式,什麽什麽屬性等等.
而他自己本身只能有定義,有約定,就是不准有函式体.
接口中定義的各個函式根屬性都不能寫訪問修飾符.
接口本身不能不能實例化.

#8


1.virtual:允许被重写,但不强制要求。声明时提供其自身实现;
2.abstract:强制要求其继承者重写。声明时不提供其自身的实现,抽象类不能被实例化;
3.interface:接口就是协议,其声明的成员(属性,方法,事件和索引器)必须由其继承的类实现。接口不能直接被实例化。

虚方法与抽象方法的区别在于,虚方法提供自身的实现,并且强制要求子类重写;而抽象方法不提供自身的实现,并且强制子类重写。

抽象类与接口很相似,但是思路不一样。接口是公开类的成员,而抽象类则是抽象类成员以要求子类继承并实现。

#9


留个脚印,学习一下

#10


虚方法与抽象方法的区别在于,虚方法提供自身的实现,并且强制要求子类重写;而抽象方法不提供自身的实现,并且强制子类重写。
===============
虚方法 好象不要求子类必须重写吧?

#11


学习 了

#12


虚方法 好象不要求子类必须重写吧?
------------------------------
呵呵,笔误。

#13


学习

#14


virtual   关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。   
  ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csref/html/vclrfVirtualPG.htm   
    
  abstract   修饰符用于表示所修饰的类是不完整的,并且它只能用作基类。   
  ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csspec/html/vclrfcsharpspec_10_1_1_1.htm   
    
  interface   
  一个接口定义一个协定。实现接口的类或结构必须遵守其协定。   
  ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csref/html/vcrefTheInterfaceType.htm   
  ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconInterfaces.htm   
    
  抽象类和接口   
  ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csspec/html/vclrfcsharpspec_13_4_5.htm

#15


翻翻旧帖子,以前有讨论这个问题的

#16


virtual(C# 参考) 

virtual 关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。例如,此方法可被任何继承它的类重写。


public virtual double Area() 
{
    return x * y;
}


虚拟成员的实现可由派生类中的重写成员更改。有关使用 virtual 关键字的更多信息,请参见使用 Override 和 New 关键字控制版本(C# 编程指南)和了解何时使用 Override 和 New 关键字(C# 编程指南)。


调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。

默认情况下,方法是非虚拟的。不能重写非虚方法。

virtual 修饰符不能与 static、abstract 和 override 修饰符一起使用。

除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。

在静态属性上使用 virtual 修饰符是错误的。

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



在该示例中,Dimensions 类包含 x 和 y 两个坐标和 Area() 虚方法。不同的形状类,如 Circle、Cylinder 和 Sphere 继承 Dimensions 类,并为每个图形计算表面积。每个派生类都有各自的 Area() 重写实现。根据与此方法关联的对象,通过调用正确的 Area() 实现,该程序为每个图形计算并显示正确的面积。

在前面的示例中,注意继承的类 Circle、Sphere 和 Cylinder 都使用了初始化基类的构造函数,例如: 



public Cylinder(double r, double h): base(r, h) {}



// cs_virtual_keyword.cs
using System;
class TestClass
{
    public class Dimensions
    {
        public const double PI = Math.PI;
        protected double x, y;
        public Dimensions()
        {
        }
        public Dimensions(double x, double y)
        {
            this.x = x;
            this.y = y;
        }

        public virtual double Area()
        {
            return x * y;
        }
    }

    public class Circle : Dimensions
    {
        public Circle(double r) : base(r, 0)
        {
        }

        public override double Area()
        {
            return PI * x * x;
        }
    }

    class Sphere : Dimensions
    {
        public Sphere(double r) : base(r, 0)
        {
        }

        public override double Area()
        {
            return 4 * PI * x * x;
        }
    }

    class Cylinder : Dimensions
    {
        public Cylinder(double r, double h) : base(r, h)
        {
        }

        public override double Area()
        {
            return 2 * PI * x * x + 2 * PI * x * y;
        }
    }

    static void Main()
    {
        double r = 3.0, h = 5.0;
        Dimensions c = new Circle(r);
        Dimensions s = new Sphere(r);
        Dimensions l = new Cylinder(r, h);
        // Display results:
        Console.WriteLine("Area of Circle   = {0:F2}", c.Area());
        Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());
        Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
    }
}


输出
  
Area of Circle   = 28.27
Area of Sphere   = 113.10
Area of Cylinder = 150.80
 

#17




abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。

在此例中,类 Square 必须提供 Area 的实现,因为它派生自 ShapesClass:




        abstract class ShapesClass
{
    abstract public int Area();
}
class Square : ShapesClass
{
    int x, y;
    // Not providing an Area method results
    // in a compile-time error.
    public override int Area()
    {
        return x * y;
    }
}


有关抽象类的更多信息,请参见抽象类、密封类及类成员(C# 编程指南)。

抽象类具有以下特性:

抽象类不能实例化。

抽象类可以包含抽象方法和抽象访问器。

不能用 sealed(C# 参考)修饰符修改抽象类,这意味着抽象类不能被继承。

从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。

在方法或属性声明中使用 abstract 修饰符以指示方法或属性不包含实现。

抽象方法具有以下特性:

抽象方法是隐式的虚方法。

只允许在抽象类中使用抽象方法声明。

因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。例如: 


public abstract void MyMethod();


实现由一个重写方法提供,此重写方法是非抽象类的成员。

在抽象方法声明中使用 static 或 virtual 修饰符是错误的。 

除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。

在静态属性上使用 abstract 修饰符是错误的。

在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性。 

抽象类必须为所有接口成员提供实现。 

实现接口的抽象类可以将接口方法映射到抽象方法上。例如:


interface I 
{
    void M();
}
abstract class C: I 
{
    public abstract void M();
}


在本例中,DerivedClass 类是从抽象类 BaseClass 派生的。抽象类包含一个抽象方法 AbstractMethod 和两个抽象属性 X 和 Y。



// abstract_keyword.cs
// Abstract Classes
using System;
abstract class BaseClass   // Abstract class
{
    protected int _x = 100;
    protected int _y = 150;
    public abstract void AbstractMethod();   // Abstract method
    public abstract int X    { get; }
    public abstract int Y    { get; }
}

class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }

    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }

    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }

    static void Main()
    {
        DerivedClass o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
    }
}


输出
x = 111, y = 161

在上面的示例中,如果试图通过使用下面的语句将抽象类实例化:


BaseClass bc = new BaseClass();   // Error


将出现错误,指出编译器无法创建抽象类“BaseClass”的实例。

#18


看看这个帖子:http://topic.csdn.net/u/20080220/16/fedb74cd-95e1-4ab5-a2bb-934c3e9f017c.html

#19


接口只包含方法、委托或事件的签名。方法的实现是在实现接口的类中完成的,如下面的示例所示:


        interface ISampleInterface
{
    void SampleMethod();
}

class ImplementationClass : ISampleInterface
{
    // Explicit interface member implementation: 
    void ISampleInterface.SampleMethod()
    {
        // Method implementation.
    }

    static void Main()
    {
        // Declare an interface instance.
        ISampleInterface obj = new ImplementationClass();

        // Call the member.
        obj.SampleMethod();
    }
}


接口可以是命名空间或类的成员,并且可以包含下列成员的签名: 

方法 

属性 

索引器 

事件 

一个接口可从一个或多个基接口继承。

当基类型列表包含基类和接口时,基类必须是列表中的第一项。

实现接口的类可以显式实现该接口的成员。显式实现的成员不能通过类实例访问,而只能通过接口实例访问,例如:

有关显式接口实现的更多详细信息和代码示例,请参见显式接口实现(C# 编程指南)。


下面的示例演示了接口实现。在此例中,接口 IPoint 包含属性声明,后者负责设置和获取字段的值。Point 类包含属性实现。



// keyword_interface_2.cs
// Interface implementation
using System;
interface IPoint
{
    // Property signatures:
    int x
    {
        get;
        set;
    }

    int y
    {
        get;
        set;
    }
}

class Point : IPoint
{
    // Fields:
    private int _x;
    private int _y;

    // Constructor:
    public Point(int x, int y)
    {
        _x = x;
        _y = y;
    }

    // Property implementation:
    public int x
    {
        get
        {
            return _x;
        }

        set
        {
            _x = value;
        }
    }

    public int y
    {
        get
        {
            return _y;
        }
        set
        {
            _y = value;
        }
    }
}

class MainClass
{
    static void PrintPoint(IPoint p)
    {
        Console.WriteLine("x={0}, y={1}", p.x, p.y);
    }

    static void Main()
    {
        Point p = new Point(2, 3);
        Console.Write("My Point: ");
        PrintPoint(p);
    }
}


输出
  
My Point: x=2, y=3

 

#20


简单来说虚函数(Virtual)已经包含了也必须包含默认的实现,所以在派生类中可以重新实现也可以不实现这些虚函数。
抽象函数(abstract)没有提供默认实现,所以在派生类中 必须实现这些抽象函数。
接口中的函数类似于抽象函数,也不提供默认实现,实现接口的类也 必须实现这些函数。
但接口可用于多继承,即,类只能从一个类继承,但可同时实现多个接口。

#21


抽象方法必须由派生的子类来实现
而虚方法派生的子类不一定会重写

虚方法在基类中可以有实现,但抽象方法不能。
虚方法可以在子类中不实现,但抽象方法必须在子类中全部实现。

虚方法提供了满足基本需要的代码,一般情况下不需要客户端重新写,如果满足不了,客户端可以覆盖。
抽象方法在抽象类中,通常抽象类提供模板方法的实现,模板方法需要一些接口,但是必须由客户端提供,抽象方法就是定义这些接口。

当觉得一个方法要实现什么功能,并且知道怎么实现功能的时候,用虚方法.
当知道方法要实现的功能,但对怎么实现不清楚的时候,用抽象方法

抽象方法是需要子类去实现的
虚方法,是已经实现了,子类可以去覆盖,也可以不覆盖

#22


mark学习

#23


学习了一下!呵呵,介绍好详细的!

#24


嗯, 有道理

#25


这些都是面向对象的特性了。

#26


恩,就是這樣

#27


说的不错

#28


受教了

#29


学习了,记录了!感谢!

#30


very good!

#31


不错。。果然是人多力量大啊

推荐阅读
  • 深入理解Java反射机制
    本文将详细介绍Java反射的基础知识,包括如何获取Class对象、反射的基本过程、构造器、字段和方法的反射操作,以及内省机制的应用。同时,通过实例代码加深对反射的理解,并探讨其在实际开发中的应用。 ... [详细]
  • 转自:http:blog.sina.com.cnsblog_67419c420100vmkt.html 1.为什么要使用blocks将一个blocks作为函数或者方法的参数传递,可 ... [详细]
  • BeautifulSoup4 是一个功能强大的HTML和XML解析库,它能够帮助开发者轻松地从网页中提取信息。本文将介绍BeautifulSoup4的基本功能、安装方法、与其他解析工具的对比以及简单的使用示例。 ... [详细]
  • 基于OpenCV的小型图像检索系统开发指南
    本文详细介绍了如何利用OpenCV构建一个高效的小型图像检索系统,涵盖从图像特征提取、视觉词汇表构建到图像数据库创建及在线检索的全过程。 ... [详细]
  • 探讨了生成时间敏感的一次性伪随机密码的方法,旨在通过加入时间因素防止重放攻击。 ... [详细]
  • 本文详细介绍了如何将After Effects中的动画相机数据导入到Vizrt系统中,提供了一种有效的解决方案,适用于需要在广播级图形制作中使用AE动画的专业人士。 ... [详细]
  • 时序数据是指按时间顺序排列的数据集。通过时间轴上的数据点连接,可以构建多维度报表,揭示数据的趋势、规律及异常情况。 ... [详细]
  • 题目描述墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令ÿ ... [详细]
  • 题目描述:给定 n 把雨伞和 m 个人,t 分钟后开始下雨。求在每个人只能使用一把雨伞的情况下,最多有多少人可以拿到雨伞。 ... [详细]
  • 系统:MacOS10.15.2,XCode11.3,swift5.0写作时间:2020-01-09说明Swift中的闭包(Closur ... [详细]
  • HDU1085 捕获本·拉登!
    问题描述众所周知,本·拉登是一位臭名昭著的恐怖分子,他已失踪多年。但最近有报道称,他藏匿在中国杭州!虽然他躲在杭州的一个洞穴中不敢外出,但近年来他因无聊而沉迷于数学问题,并声称如果有人能解出他的题目,他就自首。 ... [详细]
  • 本文详细介绍了Spring AOP注解的基本概念及其实现方式,并通过实例演示了如何在项目中使用这些注解进行面向切面的编程。旨在帮助开发者更好地理解和运用Spring AOP功能。 ... [详细]
  • GCC(GNU Compiler Collection)是GNU项目下的一款功能全面且高效的多平台编译工具,广泛应用于Linux操作系统中。本文将详细介绍GCC的特点及其基本使用方法。 ... [详细]
  • 本文介绍了在解决Hive表中复杂数据结构平铺化问题后,如何通过创建视图来准确计算广告日志的曝光PV,特别是针对用户对应多个标签的情况。同时,详细探讨了UDF的使用方法及其在实际项目中的应用。 ... [详细]
  • BL550721、特点液晶驱动输出:Common输出4线,Segment输出36线内置显示寄存器364144bit2线串行接口(SCL,SDA)内置震荡电路内置液晶驱动电源电路13 ... [详细]
author-avatar
倒转流年1990
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有