为什么接口不能有构造函数和析构函数?

7

我知道这个接口正在工作。当我开始在我的项目中编码时,我心中产生了疑问。有人能够澄清一下吗?


7
为什么他们要这样做?他们不是被创建和释放的人。实施实例才是。 - BoltClock
10个回答

23

接口是合同,而不是实现,因此无需构建或销毁它们。您只需构建和销毁可能实现接口的具体类型即可。


3

据我了解,您想知道为什么我们不能像其他对象的方法一样指定构造函数的签名,例如

    interface IApp
    {
         void App(int i, int j);
    }
    class App : IApp
    {
         // You want constructor to be only with 2 parameters
         public void App(int i, int j){ }
    }

由于首先所有接口方法都应该被实现为public,但构造函数可以被设置为private,因此无法完成,其次,方法void App(..)将仅作为类App的构造函数,对于另一个类而言,它将是另一种方法。
因此,在普通情况下,如果您想要指定具有已知参数的构造函数,请尝试使用抽象基类。

3
虽然这只是一个小点,但是其他方法也可以设置为私有的。当它们实现接口时,它们必须像您所说的那样是公共的,但构造函数在可见性方面并没有任何不同。 - Adam Lear
  1. 正如@AdamLear所说,每个方法都可以是公共的或私有的。
  2. 即使使用抽象类,您也可以在派生类中拥有私有构造函数,那么您的观点是什么?
  3. 接口“IApp”中的构造函数应该是“IApp(int i,int j)”,而不是“App(int i,int j)”,否则实现IApp的App2应该包含一个名为“App”的构造函数(??)。 踩下投票。
- Massimiliano Kraus

3
我采用了另一种方式,提出了“如果……会怎样”的问题。以下是我的结论(来自我的博客):
1. 给定一个接口IApp,该接口定义了一个名为“ctor(int)”的构造函数。
2. 定义了一个类MyApp,并实现了IApp接口。
==> 现在,MyApp类具有来自IApp的构造函数“ctor(int)”。
3. 给定第二个接口ICoolApp,该接口定义了一个名为“ctor(string)”的构造函数。
4. 类MyApp实现了ICoolApp。
==> 现在,MyApp类有两个构造函数“ctor(int)”和“ctor(string)”了。到目前为止都很好。
即使定义了具有相同签名的构造函数,显式实现也可以定义创建MyApp类的两种不同方式(就像方法已经做的那样)。
5. 调用“new MyClass(int)”创建了MyApp类的新实例。这个新的实例既是IApp,又是ICoolApp,因为它实现了这两个接口。没有问题,对吗?
==> 错了!MyApp类有两个构造函数,但实例是通过调用IApp的构造函数创建的。“ctor(string)”构造函数无法满足ICoolApp的对象创建方式。
作为结论,MyApp的实例既是IApp,又是ICoolApp,但实例的创建只满足了一个契约,即IApp的契约。由于不同的签名,因此在实例创建期间无法同时满足两个契约,尽管MyApp声称尊重/实现了这两个契约。

我真的不太理解你的意思。关于第五个问题,我使用“new MyApp(int)”创建了一个MyApp实例。现在我有了一个实现两个接口的MyApp实例。你说的“构造函数'ctor(string)'未被调用”是什么意思?好的,它没有被调用是因为实例是使用另一个构造函数创建的。那又怎样?有什么问题吗?如果你有一个类实现了来自两个不同接口的两个方法,调用其中一个方法并不意味着该对象不再遵守其他接口的规定。 - Massimiliano Kraus
1
@MassimilianoKraus 的观点是两个接口都对对象的创建有一个“期望”。由于实现了这两个接口,除非实现两个构造函数的人注意到这一点,否则不可能同时满足两个接口。在我看来,这实际上是这里最好的解释,尽管有点不太结构化。 - Steffen Winkler

1
接口定义了可以由一个或多个类实现的方法集。其抽象形式定义了契约。
接口不分配任何内存,也不实现任何方法。
接口没有初始化变量的任何功能。

0

接口只是对象之间的契约,它们本身没有任何代码。如果你给它们构造函数和析构函数,那就相当于给它们添加需要执行的代码。如果你需要在契约中进行初始化或清理操作,可以添加Initialize() 和 Uninitialize() 方法。


0

因为接口本身无法构建或销毁,它只是一个概念,一份契约。

声明和定义接口的过程就是构建接口,它们不是可以实例化的对象。


0

我认同接口是一种"契约"。就我的个人看法而言,我希望能够将构造函数签名作为这个契约的一部分进行指定。

但是,我喜欢像 Pascal 和 Ada 这样的语言,它们都非常努力地规定了一个正式的 "接口",与 "实现" 分开并且相互独立。

不管怎样,从实践和理论上讲,有很多原因可以排除构造函数(甚至构造函数定义)出接口。在 C# 和 Java 中,这些论点基本上是相同的。以下链接非常有启发性:

我基本上同意这些观点:


0

可以定义一个静态类,名称与接口相似,其中包括工厂方法或属性来生成实现接口的类实例。例如,Enumerable<T>.Empty和Comparer<T>.Default。我个人认为,如果有一种指定接口名称可用于引用静态成员的方法(通过具有相同名称的接口和静态类,能够在接口中包含静态成员,能够指定静态类与接口“关联”等),这将是有帮助的。不幸的是,在任何 .net 语言中,我都不知道是否有这样的功能;最好的方法就是使用名称类似的静态类(如IEnumerable/Enumerable和IComparer/Comparer)。

顺便说一句,如果接口可以包括静态内容,一个很好的额外功能就是让它们包括自己的扩展方法。例如:

  void SetBounds(int x, int y, int width, int height, BoundsSpecified specified);
  static void SetBounds(int x, int y, int width, int height)
    { It.SetBounds(x, y, width, height, BoundsSpecified.All); }
  static void SetSize(int width, int height)
    { It.SetBounds(0, 0, width, height, BoundsSpecified.Size); }

为了让接口向其用户公开许多常见函数的重载版本,而不需要所有实现都包含必要的样板代码来实现它们。


0

我也曾经问过自己这个问题,现在似乎有一个解释:

接口合同描述对象做什么,而不是如何做。构造函数可能与如何做更相关,因此我们不能将其作为合同的一部分。

接口的客户端希望收到一个已经构建好的对象,因此他们不关心构造函数的签名。至于将创建该对象的代码,它已经知道要创建什么具体对象,因此它知道构造函数的签名。


0

确实,接口没有构造函数,因为它们不知道哪种派生类将要实现它。

但是,我们可以有一个虚析构函数,以防止编译器隐式创建移动操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接