【问题标题】:OOP: understanding AbstractionOOP:理解抽象
【发布时间】:2014-07-19 19:57:51
【问题描述】:

为了更好地理解abstraction,我浏览了许多文章和一些 Stack Overflow 问题,但有点困惑。这是我一直在阅读的内容:here

抽象是“代表本质特征而不 代表背景细节。”抽象让你专注于 对象做什么而不是它如何做。

给出的代码:

abstract class MobilePhone
}
    public void Calling();
    public void SendSMS();
}

public class Nokia1400 : MobilePhone
{

}

public class Nokia2700 : MobilePhone
{
    public void FMRadio();
    public void MP3();
    public void Camera();
}

我的问题是,当我们继承 abstract class 时,我们不是在子类中实现细节吗?
call() 和 sendSms() 在超类型中没有任何实现,所以当我们在子类中实现它时,我们也应该知道背景细节。那么抽象在这个例子中实际上是如何工作的呢?

编辑:如果你来这里寻求帮助,这些人给出了最佳答案:Complexity Sergey Berezovskiy

【问题讨论】:

  • 在您的示例中,simplay 表示 Calling 和 SendSms 是每部手机中 MobilePhone 的核心功能,它是可用的,因此当您的手机发生变化时,您无需编写调用和 sendmsg 的方法只能从抽象类中使用它,没有人可以更改它,因为抽象不允许创建对象
  • @DhavalPatel 和实现细节将在这两个方法中提供对吧?
  • 是的,你必须在你的抽象类中实现这两个方法,因为如果你是非抽象方法,那么你必须有一个实现。基本抽象去掉代码冗余,不用一遍遍写代码

标签: c# class oop inheritance


【解决方案1】:

据我回忆,实现一个抽象类,你填写主体。

这就像一份合同。

当您使用该抽象类并实现它时,您同意拥有这些方法签名(该方法名称、那些参数、该返回类型)和那些变量。

好处是,如果一个类实现了它,你就知道它(实现它的类)可以通过这种方式进行通信(它有那些方法名、那些变量)。所以抽象类就像是 API 的基础。

【讨论】:

  • 请记住,抽象类可以有实现细节(甚至内部根本没有抽象方法,只是声明为抽象以防止实例化),因此调用抽象类“就像API的基础一样"并不完全准确。使用这个关于接口的描述会更准确,因为它们并不打算包含任何实现细节。
  • @user3613916 啊是的,只是我当时使用的界面,十多年前。我现在记得 abstract 是相似的,尽管我几乎没有使用过它。很好的修正。
【解决方案2】:
abstract class C{
public abstract void met1();
public void met2(){
    System.out.println("Hello");
}
}

在抽象中,如果您要扩展抽象类,则必须实现抽象类的无主体方法,而在抽象类中实现的方法可能会或可能不会在子类中获得Overridden

所以在上面的类中,如果你扩展Class C,你必须在你的类中实现met1,而met2 是可选的,如果你愿意,你甚至可以覆盖它。

@Override
public void met2(){
    super.met2();
}

所以抽象实际上是对专注于 SUPERCLASS 的查看者隐藏 SUBCLASS 的实际实现。

举例:

考虑抽象类 Dog,它具有类似 bark() 的方法,但扩展 Dog 的类将有自己的实现,例如,您有像 BullDog 这样扩展 Dog 的类。

【讨论】:

  • 所以你的意思是这两种方法的实现细节 public void Calling();公共无效发送短信();将在抽象类中提供,该实现将在子类中使用?
  • 抽象中没有(Body Less)声明,但子类中必须有实现。
【解决方案3】:

你可以有抽象方法和虚拟方法

抽象方法必须由扩展类实现,并且没有主体。

Virtual 方法确实有一个主体,但不需要被覆盖。如果不是,则执行基类的虚方法体。

有一些注意事项,但这是主要思想

public abstract class MyBase
{
    public abstract void MethodMustBeImplemented();
    public virtual void DoesNotHaveToBeOverwritten()
    {
      //Do WORk
    }
}


public class Implementor: MyBase
{

}

这将引发编译时错误,因为 MethodMustBeImplemented() 尚未被覆盖。

但是下面的很好

public class Implementor: MyBase
{
    public override void MethodMustBeImplemented()
    {
      //Do WORk
    }
}

【讨论】:

  • 请确认当我们将类标记为抽象时,我们不需要实现所有抽象/非抽象方法
  • 在C#中,只有那些标记为abstract的需要被覆盖。
【解决方案4】:

让我们为您的报价添加缺失的细节:

抽象代表基本特征[客户端代码需要] 不代表背景细节[给客户代码]。 [什么时候 你使用]抽象[它]让你专注于对象的作用 而不是它是如何做到的[因为你不知道哪个类 实现它]。

我相信现在它已经清楚了。您应该从客户的角度来看待抽象,即从将使用您的手机的代码。抽象不是必需的 abstract 类(一个有点误导的术语)——它也可以是一个接口。

真实示例 - 当您作为电视机的客户时,您使用电视机的抽象(应该有不同的频道、音量控制等),但是您不关心这些抽象的哪个确切实现被提供给您(如果您需要的电视抽象的所有功能都已实现)。客户应该满意,他应该远离细节。我敢打赌你只是在看电视,而不是一些特别的东芝 NX-42C?

【讨论】:

  • 缺少细节真的很有帮助......!
【解决方案5】:

首先,您的代码中有几个问题。

  • 抽象类确实包含没有主体的方法并且不是抽象的,所以这是无效的。您应该将方法抽象化,或者在其中提供一个主体。当您想要拥有一个主体但又希望能够覆盖该方法时,必须应用 virtual 关键字。 因此,这是您对抽象类的选择:​​i>

没有主体的方法:

abstract class MobilePhone
{
    public abstract void Calling();
    public abstract void SendSMS();
}

具有可被覆盖的主体的方法:

abstract class MobilePhone
{
    public virtual void Calling()
    {
        // Code goes here.
    }

    public virtual void SendSMS()
    {
        // Code goes here.
    }
}

具有无法被覆盖的主体的方法:

abstract class MobilePhone
{
    public void Calling()
    {
        // Code goes here.
    }

    public void SendSMS()
    {
        // Code goes here.
    }
}

然后还有几个问题。您的抽象类不提供默认情况下将对象设为私有的构造函数,因此您的类 Nokia1400 和 Nokia2700 无法从基类继承,因为基类比抽象类更难访问。

现在,根据您创建抽象类的方式,实现它的类必须满足一些要求:

  • 当您的基类确实包含抽象成员时,它应该在您的继承类中实现。
  • 当您的基类确实包含虚拟成员时,它不应在您的继承类中实现,但可以根据需要对其进行覆盖。

然后,您的最后一个类也没有编译,因为它确实包含没有主体的方法。只有当它们是抽象的并且它们必须在抽象类中时才允许使用这些类型的方法。

这是基于您的代码的示例:

public abstract class MobilePhone
{
    public virtual void Calling()
    {
        Console.Write("Calling");
    }

    public abstract void SendSMS();
}

public class Nokia1400 : MobilePhone
{
    public override void SendSMS()
    {
        Console.WriteLine("Sending SMS from Nokia 1400.");
    }
}

public class Nokia2700 : MobilePhone
{
    public void FMRadio()
    {
        Console.WriteLine("FM Radio");
    }

    public void MP3()
    {
        Console.Write("MP3");
    }

    public void Camera()
    {
        Console.WriteLine("Camera");
    }

    public override void SendSMS()
    {
        Console.WriteLine("Sending SMS from Nokia 2700.");
    }
}

所以,一篇相当长的帖子,但我希望它有所帮助。

【讨论】:

  • 这是一个很好的解释,如果你有时间你也可以在这个代码项目文章中参考这些更正codeproject.com/Articles/600449/…
  • 我的意思是你提出了非常好的观点(正如你指出的代码中的一些问题让我明白了整个想法)你也可以在我从上面提到的链接中得到这篇文章的地方提出这个建议。您的回答比那篇文章更有帮助。它可能会帮助将来阅读该文章的其他人
  • 我会做我能做的,因为我不知道我可以建议对 CodeProject 上的文章进行编辑并且没有帐户。如果本文帮助您理解该主题,请考虑将其标记为问题的答案。
【解决方案6】:

由于基类被声明为抽象,它不能被实例化,所以你不能从基类调用那些抽象方法,只能从实现了上述抽象类的派生类中调用。

当你将类声明为抽象时,你说这个类不能被实例化。然后您可以在类中声明抽象方法,因为您不需要实现它们,因为无论如何都不能调用它们。现在,尽管从您的基类派生的任何非抽象类都必须实现这些方法才能完全允许实例化。

【讨论】:

    【解决方案7】:

    你的困惑来自于你必须区分:

    抽象类&抽象方法

    抽象类永远不能被实例化,它必须被另一个类继承,然后继承的类才会被实例化。

    现在回到抽象类:它可以有两种类型的方法: - 普通方法(如您的示例调用和发送消息)。贝克。这些正常的方法,它们被认为是用空体实现的,所以继承类不需要实现它们[这让你感到困惑]

    -abstract 方法:这些方法以关键字“abstract”为前缀,一旦存在关键字abstract,那么继承类应该实现它们

    进一步澄清: 如果方法调用()和发送短信()我们以“抽象”为前缀,那么它应该被实现

    --

    现在虚拟方法和覆盖是另一个概念,如果你还有兴趣我可以谈谈它

    【讨论】:

      猜你喜欢
      • 2019-12-11
      • 1970-01-01
      • 2021-09-24
      • 1970-01-01
      • 2016-11-28
      • 2013-05-30
      • 1970-01-01
      • 1970-01-01
      • 2021-07-07
      相关资源
      最近更新 更多