为什么类继承和接口实现会涉及对象?

Why does class inheritance and interface implementation involve objects?

提问人:bokabokaboka 提问时间:10/15/2023 最后编辑:bokabokaboka 更新时间:10/26/2023 访问量:82

问:

了解类之间的区别也很重要 继承和接口继承(或子类型化)。类 继承根据另一个对象的实现来定义另一个对象的实现 对象的实现。简而言之,它是一种代码和 表示共享。相反,接口继承(或 subtyping) 描述何时可以使用对象代替 另一个。
这两个概念很容易混淆,因为许多语言没有区分 明确。在C++和Eiffel等语言中,继承意味着两个接口 和实现继承。在 C++ 中继承接口的标准方法是 从具有(纯)虚拟成员函数的类公开继承。纯净的界面 继承可以在 C++ 中通过从纯抽象公开继承来近似 类。纯实现或类继承可以用 private 近似 遗产。在 Smalltalk 中,继承意味着实现继承。您可以 将任何类的实例分配给变量,只要这些实例支持该操作 对变量的值执行。---《设计模式:面向对象的可重用元素》 软件第一版》

  1. 继承,不就是子类从父类“继承”属性和方法吗? 它如何成为“一个对象的实现与另一个对象的实现”? 当我在代码中实现从类 A 继承的类 B 时,我根本不实例化任何对象!

  2. 接口不就是一种特殊的抽象类吗?(与抽象类相比,接口只声明方法,不声明属性或字段。当一个具体的类实现一个接口时,它不就是一个继承了“接口”并实现接口中声明的方法的类吗?这如何变成“一个对象可以代替另一个对象”? 当我在代码中让类 B 实现接口 A 时,我根本不实例化任何对象!

对象 OOP 设计模式 接口

评论

0赞 Bergi 10/15/2023
"我不实例化任何对象“是无关紧要的。您的程序最终将实例化并使用此类对象,否则您不会为它们定义类。对象是目标,类定义只是描述其行为的一种手段。Re 1:“另一个对象实现”是指“另一个对象将使用的(方法)实现”。Re 2:不,接口不仅仅是一个抽象类。这里的接口(特别是关于“子类型”)是类型系统中类型

答:

1赞 ruakh 10/15/2023 #1

术语会随着时间的推移而演变;如今,你听到“界面”,就会想到Java、C++和Go等语言的特性,但是当设计模式在1994年问世时,这些语言都还不存在。因此,当它谈到“接口继承”时,它不是它所指的。interface

相反,通过“接口”,它意味着类向其客户端公开的一组功能。当应用于 Java 时,这通常意味着它的公共方法——它们的名称、签名和约定——甚至是 Java 意义上的任何“接口”都没有指定的方法。

在Java等语言中,所有的继承都是“接口继承”;如果类 A 扩展了类 B,那么它会自动实现类 B 的接口(嗯,有一些边缘情况——例如,java.sql.Timestamp 的 Javadoc 说虽然它扩展了 java.util.Date,但我们应该假装它没有,因为它不能 100% 正确地表现为 java.util.Date——但至少就 Java 语言本身而言, 所有的继承都是接口继承,有些类只是有错误。;-) )但对于某些语言来说,情况并非如此;例如,C++ 允许类 A 以“私有”方式从类 B 继承,其中类 A 具有类 B 的所有方法,但它们都是 ,因此客户端无法调用它们。在这种继承中,实现是继承的,但接口不是。这就是设计模式做出这种区分的原因。private

评论

0赞 bokabokaboka 10/15/2023
那么,书中所说的“类继承”,其实就是“实现继承”呢?
0赞 ruakh 10/15/2023
@bokabokaboka:是的。我实际上不确定它为什么使用“类继承”一词;当时的“类”(在Simula、Smalltalk、C++等中)和现在基本上是一回事,C++甚至有抽象类,所以“类继承”似乎不是指代实现继承而不是接口继承的非常精确的方式。但这肯定是它的意思。
0赞 bokabokaboka 10/16/2023
我可以这样理解吗:书中提到的类继承是指继承抽象类(同时包含数据和方法声明),而接口继承是指继承接口(仅包含方法声明,不包含数据项)?在这里,数据项是指属性。
0赞 ruakh 10/16/2023
@bokabokaboka:对不起,我不确定你从哪里得到的;“类继承”与抽象类没有任何关系。“类继承”大致是指子类继承实现(它可能会也可能不会向其客户端公开),而“接口继承”是指子类继承方法规范(它可以为其提供自己的实现)。在 C# 中,每当一个类从另一个类继承时(可以说,每当它使用默认方法实现接口时),您就会有“类继承”,并且 [续]
0赞 ruakh 10/16/2023
[续] 每当一个类从另一个类继承,或者每当一个类或结构实现一个接口时,你都有“接口继承”。请注意,在 C# 中,可以在没有类继承的情况下进行接口继承,但不能在没有接口继承的情况下进行类接口继承。但是在某些语言中,例如 C++,可以有没有接口继承的类接口;也就是说,C++ 允许类 A 从类 B 继承,而不会实际向客户端公开类 B 的功能。
0赞 StepUp 10/17/2023 #2

它如何成为“一个对象在另一个对象的实现方面的实现”?当我在代码中实现从类 A 继承的类 B 时,我根本不实例化任何对象!

让我通过 C# 举个例子:

public abstract class Animal
{
    public virtual string WhoIAm() 
    {
        return "I am an animal"; // Class inheritance defines an object's 
                                 // implementation in terms of
                                 // another object's implementation. 
    }
}


public class Cow : Animal
{

}

让我们运行上面的代码:

Animal cow = new Cow();
cow.WhoIAm(); // "I am an animal" - this is an example of class inheritance 
              // defines an object's implementation in terms of
              // another object's implementation. 

但是,您可以在不违反 Liskov 替换原则的情况下覆盖一些行为:

public class Cow : Animal
{
    public override string WhoIAm()
    {
        return "I am a cow!:)";
    }
}

这如何变成“一个对象可以代替另一个对象”?

界面类似于对对象外观的描述。例如,牛通常有四条腿,上面写着“哞哞”。因此,让我们创建以下描述或接口:

public interface IAnimal
{
    string WhoIAm();
}

然后,我们将创建上述描述的具体实现:

public class Cow : IAnimal
{
    public string WhoIAm()
    {
        return "I am a cow!:)";
    }
}

public class Pig : IAnimal
{
    public string WhoIAm()
    {
        return "I am a pig!:)";
    }
}

然后,您可以使用此描述或接口的任何具体实现。可以这样完成:

IAnimal animal = new Cow();
animal.WhoIAm(); // "I am a cow!:)"

animal = new Pig();
animal.WhoIAm(); // "I am a pig!:)"