抽象方法,虚方法

BXS_null 2018-08-13 04:28:43
加精
抽象方法虚方法都是可以被重写的,区别就是一个重写前已经有方法体了,一个没方法体。一个的基类是抽象类,一个是非抽象类。那这两种方法分别在使用在什么场景呢?各自的优劣是啥
...全文
3263 42 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
tq1086 2018-11-09
  • 打赏
  • 举报
回复
引用 9 楼 caozhy 的回复:
抽象方法其实是虚方法的特例。你看il代码,抽象方法会自动添加 virtual 的修饰符。既然抽象方法是虚方法的特例,那么它特殊就在,基类是抽象类没办法实现的情况。比如说一个抽象表示形状的类,它的“面积”就没有意义,必须是派生类(比如三角形类、四边形类、圆类等)去实现了。

从性能角度,虚方法和抽象方法有区别吗?抽象方法也是动态绑定的吗?
Logerlink 2018-08-28
  • 打赏
  • 举报
回复
引用 11 楼 closurer 的回复:
虚方法就是具有默认实现的抽象方法。

精辟
Peter-ma 2018-08-17
  • 打赏
  • 举报
回复
能解决这个就可以结贴了
蒹葭残辉 2018-08-17
  • 打赏
  • 举报
回复
虚方法允许重写,抽象方法必须重写
天语星坠 2018-08-15
  • 打赏
  • 举报
回复
感觉好抽象啊,厉害了啊
vbvb谁有会员 2018-08-15
  • 打赏
  • 举报
回复
有没有csdn分数
  • 打赏
  • 举报
回复
引用 19 楼 hanjun0612 的回复:
[quote=引用 18 楼 duanzi_peng 的回复:]
[quote=引用 1 楼 hanjun0612 的回复:]
就我个人理解而言。
抽象方法代表你先定下一个行为准则,你没有考虑好具体的实现,但是子类必须要实现这个行为。
而虚方法是代表子类可以重写这个行为,你可以有和父类不同的实现逻辑,或者说你就不重写,默认和父类的行为一模一样。

这个应该算概念上的区别。

这个解释的都可以了,不动手进行设计 是不太容易理解的。[/quote]
我以为你已经失踪了[/quote]
没有呢 之前从郑州离职了 现在在北京了 期间消失了近两个月
游北亮 2018-08-15
  • 打赏
  • 举报
回复
引用 35 楼 weixin_40068689 的回复:
能不能顺便再问一下,接口应用场景,就是跟抽象方法的区别


你这个问题应该是接口跟抽象类的区别,这个随便搜索一下,已经很多讨论了,

实际应用中,这2者是经常混淆的,而且即使混着用也不会有太大的问题,要注意的就是一个子类只能有一个父类,但是可以实现多个接口。
wanghui0380 2018-08-15
  • 打赏
  • 举报
回复
还是上面的例子,如果看问题的人,角度不同。就是另外的结果

他可以说,我主题是塑料,我这里是“用塑料做的杯子”我可以先抽象塑料,然后在把容器当接口。

这个也没啥问题,毕竟塑料是物理存在(实),容器是语言存在(名)。所以我们其实并不纠结这个问题,要解决的东西不同。重点不同都没关系,毕竟大家都能描述出“塑料杯子”的特性,并且都能实现一个“塑料杯子”出来
number1killer 2018-08-15
  • 打赏
  • 举报
回复
虚方方法可以不重写,但是抽象方法必须重写。另外虚方法允许调用同一个方法的不同版本,基类的虚方法可能会在派生类中实现。
wanghui0380 2018-08-15
  • 打赏
  • 举报
回复
所以在20年前最正统的“对象设计”教材里,会去讲“名实之辩”(语言(名)和世界(实)的关系之争)会去讲“主谓宾定状补”

塑料杯子--杯子是主语--杯子是容器
wanghui0380 2018-08-15
  • 打赏
  • 举报
回复
引用
能不能顺便再问一下,接口应用场景,就是跟抽象方法的区别


接口和抽象的区别在于,内涵与外延。抽象类关注内涵,接口主要关注外延。或者另一种解释也行,比如物理上存在的我们叫抽象类,非物理的存在我们叫接口,这样也行。其实这就是一种描述,我们做对象设计,总体上就是写说明文,说明本质上他是什么,然后有什么其他的外延的功能。

比如我们说比较常见的东西集合类,他的本质是集合。而他的外延功能可迭代。所以如果是做设计你可以抽象一个集合抽象,然后在设计一个迭代接口。

当然内涵和外延取决与编写者看问题的角度,辟之蜜糖,吾之砒霜。即使是同样的东西,看问题的人不一样,关注的东西也不一样。所以他们以谁为主,谁为辅,那就各取所需了
BXS_null 2018-08-15
  • 打赏
  • 举报
回复
引用 32 楼 youbl 的回复:
从自己的项目里找了一个例子,缓存实现类,
有的业务要用内存缓存,有的业务不能用内存缓存,要用Redis缓存,
那么框架层要提供不同的实现,各业务根据需求修改配置文件,灵活变更自己想要的缓存方案:


// 缓存操作父类
public abstract class AbstractCache : ICache
{
// 读取单个缓存,不同的缓存实现不同,所以无法提供默认实现
public abstract T Get<T>(string key);

// 批量读取缓存的默认实现
public virtual IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
{
var resultDic = new Dictionary<string, T>();
foreach (var item in items)
{
resultDic.Add(item, Get<T>(item));
}
return resultDic;
}
}


下面是内存缓存实现,批量方法直接用父类的就ok了

// 基于 System.Web.HttpRuntime.Cache 运行时缓存的封装
public class HttpRuntimeCache : AbstractCache
{
public override T Get<T>(string key)
{
var ret = HttpRuntime.Cache.Get(key);
if (ret == null)
{
return default(T);
}
return ClonedCast<T>(ret);
}
}


下面是Redis缓存实现,批量方法也可以直接用父类的,但是性能比较低下,所以重写了

public class RedisCache : AbstractCache
{
public override T Get<T>(string key)
{
byte[] data;
using (var client = GetManager().GetClient())
{
data = client.Get<byte[]>(key);
}
if (data == null)
return default(T);
return DeSerializ<T>(Encoding.UTF8.GetString(data));
}

// 批量读取缓存优化实现
public override IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
{
IDictionary<string, byte[]> data;
using (var client = GetManager().GetClient())
{
data = client.GetAll<byte[]>(keys);
}
var resultDic = new Dictionary<string, T>();
foreach (var kvp in data)
{
resultDic.Add(kvp.Key, kvp.Value == null ? default(T) : DeSerializ<T>(Encoding.UTF8.GetString(kvp.Value)));
}
return resultDic;
}
}
能不能顺便再问一下,接口应用场景,就是跟抽象方法的区别
weixin_42977923 2018-08-15
  • 打赏
  • 举报
回复
很好,今天真是长见识了。写的很到位
BXS_null 2018-08-15
  • 打赏
  • 举报
回复
引用 23 楼 youbl 的回复:
楼主想问的是什么样子的场景吧?
我举一个抽象类的场景吧,你想开发一个兼容SqlServer和MySql的数据库操作类:
abstract class SqlHelper{
// 不知道具体实现是啥数据库,所以只能用抽象方法
abstract object GetFirstRec();
}

public class SqlServerHelper : SqlHelper {
override object GetFirstRec(){
var sql = "select top 1 * from tb";
return xxx;
}
}
public class MySqlHelper : SqlHelper {
override object GetFirstRec(){
var sql = "select * from tb limit 1";
return xxx;
}
}



再举一个虚方法的例子:
abstract class Animal{
// 动物移动,默认用脚走路,这个暂时不考虑没脚的
virtual void Move(){
Move on foot;
}
}
public class Human : Animal {
// 人只能用脚走路,所以不用重写
}

public class Bird : Animal {
// 为了性能,重写,鸟用翅膀飞
virtual void Move(){
Move on wing;
}
}


哈哈,可能不一定恰当,能理解就好,
实际场景中,看你的需要了。
哦。。感谢,懂了,就是说这个方法是必须要的,但是可能根据不同的情况有不同的写法。这是属于工厂的概念吗
游北亮 2018-08-15
  • 打赏
  • 举报
回复
从自己的项目里找了一个例子,缓存实现类,
有的业务要用内存缓存,有的业务不能用内存缓存,要用Redis缓存,
那么框架层要提供不同的实现,各业务根据需求修改配置文件,灵活变更自己想要的缓存方案:


// 缓存操作父类
public abstract class AbstractCache : ICache
{
// 读取单个缓存,不同的缓存实现不同,所以无法提供默认实现
public abstract T Get<T>(string key);

// 批量读取缓存的默认实现
public virtual IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
{
var resultDic = new Dictionary<string, T>();
foreach (var item in items)
{
resultDic.Add(item, Get<T>(item));
}
return resultDic;
}
}


下面是内存缓存实现,批量方法直接用父类的就ok了

// 基于 System.Web.HttpRuntime.Cache 运行时缓存的封装
public class HttpRuntimeCache : AbstractCache
{
public override T Get<T>(string key)
{
var ret = HttpRuntime.Cache.Get(key);
if (ret == null)
{
return default(T);
}
return ClonedCast<T>(ret);
}
}


下面是Redis缓存实现,批量方法也可以直接用父类的,但是性能比较低下,所以重写了

public class RedisCache : AbstractCache
{
public override T Get<T>(string key)
{
byte[] data;
using (var client = GetManager().GetClient())
{
data = client.Get<byte[]>(key);
}
if (data == null)
return default(T);
return DeSerializ<T>(Encoding.UTF8.GetString(data));
}

// 批量读取缓存优化实现
public override IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
{
IDictionary<string, byte[]> data;
using (var client = GetManager().GetClient())
{
data = client.GetAll<byte[]>(keys);
}
var resultDic = new Dictionary<string, T>();
foreach (var kvp in data)
{
resultDic.Add(kvp.Key, kvp.Value == null ? default(T) : DeSerializ<T>(Encoding.UTF8.GetString(kvp.Value)));
}
return resultDic;
}
}



NewAlexanderITKing 2018-08-15
  • 打赏
  • 举报
回复
成为领队人物的时候后那就是你用抽象方法的时候后 等你成为技术总监的时候后 就是使用接口的时候后 我是这么认为的。
threenewbee 2018-08-14
  • 打赏
  • 举报
回复
抽象方法其实是虚方法的特例。你看il代码,抽象方法会自动添加 virtual 的修饰符。既然抽象方法是虚方法的特例,那么它特殊就在,基类是抽象类没办法实现的情况。比如说一个抽象表示形状的类,它的“面积”就没有意义,必须是派生类(比如三角形类、四边形类、圆类等)去实现了。
圣殿骑士18 2018-08-14
  • 打赏
  • 举报
回复
引用 25 楼 wanghui0380 的回复:
大巧若拙,大智若愚

粗枝大叶不是错误,能做到粗枝大叶,才是真本事来着

能把粗枝大叶解释出花来,算你赢了。
wanghui0380 2018-08-14
  • 打赏
  • 举报
回复
大巧若拙,大智若愚

粗枝大叶不是错误,能做到粗枝大叶,才是真本事来着
加载更多回复(22)

62,243

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧