【问题标题】:Interfaces vs. Abstract Classes or polymorphism in general接口与抽象类或一般多态性
【发布时间】:2014-02-07 09:39:31
【问题描述】:

我在理解接口和抽象类的使用之间的区别时遇到了问题。

例如,请看下面的 UML 图:

这两者有什么区别?

【问题讨论】:

标签: oop interface abstract-class


【解决方案1】:

我将提供一个带有代码的解释和一个简短的解释。如果不想看,直接跳到下面的“简单的英文解释”即可。


代码说明

  • 在 C++ 术语中,抽象类是实现某些方法但不实现其他方法的类。这意味着:您可以使用他们的一些方法,但您必须实现未实现的方法。

  • 接口是 C++ 中的纯类,也就是说,一个不实现任何东西的类,如果你希望你的类符合那个接口,你必须实现所有东西

例如- 试试下面的链接

#include <iostream>
using namespace std;

// Shape is abstract class: some methods are already available, some are not
class Shape
{
public:
  // This is already implemented and ready for polymorphism
  virtual void area() { cout<<"Shape area"<<endl;}
  // You MUST implement this
  virtual void implement_me() = 0;
};

class Circle : public Shape
{
public:
  virtual void area() { cout<<"Circle area"<<endl;}
  void implement_me() { cout<<"I implemented it just because I had to"<<endl;}
};

class HalfCircle : public Circle
{
public:
  virtual void area() { cout<<"HalfCircle area"<<endl;}
};


// ShapeInterface is a pure class or interface: everything must be implemented!
class ShapeInterface
{
public:
  virtual void area() = 0;
};

class CircleFromInterface : public ShapeInterface
{
public:
  // You MUST implement this!
  virtual void area() { cout<<"CircleFromInterface area from interface"<<endl;};
};



int main() {

    Shape* ptr_to_base = new HalfCircle();
    ptr_to_base->area(); // HalfCircle area, polymorphism
    ptr_to_base->Shape::area(); // Shape area
    ptr_to_base->implement_me(); // from Circle


    ShapeInterface *ptr_to_base_int = new CircleFromInterface();
    ptr_to_base_int->area(); // Just the derived has it

    return 0;
}

http://ideone.com/VJKuZx


纯英文解释

如果您想要过于简化的版本:

  • 接口通常是您需要完全遵守的“合同”:您需要同意所有内容并实施所有内容,否则它不起作用。

  • 抽象类是部分契约,有些事情您必须同意/实施,但还有一些其他内容已经存在,您可以选择是否重新实施它(覆盖)或者只是懒惰并使用现有的。

【讨论】:

  • 非常感谢!我一直想知道 C++ 中的接口是如何完成的,因为它缺少“接口”关键字。所以基本上,接口的每个方法都应该是虚拟的,因为它总是“指向”一个具体的类实现方法?
  • 您或多或少地了解了这个概念。接口是您需要从头开始实现的东西。通常会传递一个指向接口的指针,它旨在指向实现所有这些方法的完整对象(也许还有其他东西,但你不在乎,你只会关心 中的那些方法界面)。抽象类是“部分”接口,它们提供了一些您需要实现的“空白字段”,还提供了一些随时可用(或覆盖)的方法。我主要指的是 C++,因为这是我最了解的语言,但 OOP 概念是相同的。
【解决方案2】:

抽象类用于处理子类之间的代码重复,因为它们可以共享共同的逻辑和数据。接口只是定义了实现者的共同契约。

所以,如果没有通用的实现可以共享,那就使用接口(我总是从接口开始)。如果会出现一些通用实现,则提取抽象基类并将通用代码移到那里。但即使在这种情况下,我也将接口保持在层次结构中,因为它很容易模拟并且更抽象,这使得其他类根本不依赖任何实现。


在您的情况下,我认为 CircleHalfCircle 共享一些实现。所以我会把通用代码移到Circle 并从它继承HalfCircleЖ

public class Circle : IShape
{
    public double Radius { get; set; }
    public virtual double Area
    {
        get { return Math.PI * Radius * Radius; }
    }
}

public class HalfCircle : Circle
{
    public override double Area
    {
        get { return base.Area / 2; }
    }
}

如果所有形状共享一些数据或计算面积的逻辑,那么为这个公共代码声明基本抽象Shape 类是有意义的。但是如果你看正方形的面积计算,圆形没有什么共同点:

public class Square : IShape
{
    public double Side { get; set; }

    public double Area
    {
        get { return Side * Side; }
    }
}

所以IShape 接口就足够了,因为类只共享契约:

public interface IShape
{
    double Area { get; }
}

【讨论】:

    【解决方案3】:

    可能使用抽象类的继承关系通常可以描述为“是”,而接口的实现是“可以”。这个概念在选择使用哪个时会有所帮助。

    因此,如果方形“是”形状,那么继承将是一种可接受的建模这种关系的方式。

    此外,抽象类将使您能够提供通用功能。接口不能包含任何实现。

    【讨论】:

      猜你喜欢
      • 2011-01-09
      • 2017-02-19
      • 2020-08-01
      • 1970-01-01
      • 2016-03-24
      • 2010-12-01
      • 1970-01-01
      • 2012-11-06
      相关资源
      最近更新 更多