代码之家  ›  专栏  ›  技术社区  ›  hhafez

在宾语C中,继承和分类有什么区别?

  •  57
  • hhafez  · 技术社区  · 16 年前

    有人能给我解释一下目标C中类别和继承的区别吗?我读过 the entry in Wikipedia 关于类别的讨论和继承的讨论没有什么不同。我还看了《开放式iPhone开发》一书中关于这个主题的讨论,但我还是不明白。

    7 回复  |  直到 9 年前
        1
  •  96
  •   Jack Humphries    11 年前

    有时候,继承似乎比它的价值更麻烦。当您想向一个现有的类中添加一些改变了该类行为的东西时,可以正确地使用它。

    对于一个类别,您只希望现有对象做更多的工作。如前所述,如果您只希望有一个处理压缩的字符串类,则不需要对该字符串类进行子类化,只需创建一个处理压缩的类别。这样,就不需要更改已经使用的字符串类的类型。

    线索是在限制类别只能添加方法的情况下,不能使用类别向类添加变量。如果类需要更多的属性,那么它必须是子类的(编辑:我相信你可以使用关联存储)。

    类别是一种添加功能的好方法,同时符合面向对象原则,优先选择组合而不是继承。

    编辑:2012年1月

    现在一切都变了。使用当前的llvm编译器和现代的64位运行时,可以向类中添加ivar和属性。 扩展 (不是类别)。这允许您将私有的ivar从公共接口中保留出来。但是,如果您为IVAR声明属性,它们仍然可以通过KVC访问/更改,因为在Objective-C中仍然没有私有方法。

        2
  •  17
  •   Terry Wilcox    16 年前

    类别允许您向现有类添加方法。因此,您可以直接将nsdata添加到nsdata类中,而不是将nsdata子类添加到新的加密方法中。应用程序中的每个nsdata对象现在都可以访问这些方法。

    要了解这有多有用,请查看: CocoaDev

        3
  •  11
  •   amrox    15 年前

    目标C类别的一个最受欢迎的示例是nsstring。NSCOPE是在基础框架中定义的,它没有视图或窗口的概念。但是,如果在cocoa应用程序中使用nsstring,您会注意到它会响应如下消息 – drawInRect:withAttributes: .

    AppKit为NSstring定义了一个类别,该类别提供了其他绘图方法。类别允许将新方法添加到现有类中,因此我们仍然只处理nsstring。如果AppKit不是通过子类化来实现绘图,我们必须处理“AppKitStrings”或“NSSDrawableStrings”之类的问题。

    类别允许您向现有类添加应用程序或特定于域的方法。它可以非常强大和方便。

        4
  •  4
  •   Martijn Pieters    12 年前

    如果作为一个程序员,你被赋予了一套完整的代码库或应用程序的源代码,你可以疯狂地改变你需要的任何东西,用这些代码来实现你的编程目标。

    不幸的是,这种情况并不总是如此,甚至不可取。很多时候,你会得到一个二进制库/对象工具包和一组要处理的头文件。

    然后一个类需要一个新的功能,这样您可以做以下几件事:

    1. 创建一个新的类整体而不是一个股票类——复制它的所有函数和成员,然后重写所有代码以使用新的类。

    2. 创建一个包含stock类作为成员(合成)的新包装类,并重写代码库以使用新类。

    3. 库中用于更改代码的二进制补丁(祝您好运)

    4. 强制编译器将新类视为旧类,并希望它不依赖于内存中的某个大小或位置以及特定的入口点。

    5. 子类专门化——创建子类以添加功能并修改驱动程序代码以使用子类——理论上应该没有什么问题,如果需要添加数据成员,这是必要的,但是内存占用将有所不同。在子类中同时提供新代码和旧代码,并选择要使用的代码、基类方法或重写方法,这样做的好处是。

    6. 用包含方法的类别定义修改必要的objc类,以执行您想要的操作和/或重写stock类中的旧方法。

      这还可以修复库中的错误,或者为新的硬件设备或其他设备自定义方法。它不是万能药,但它允许在不重新编译未更改的类/库的情况下添加类方法。原始类在代码、内存大小和入口点上都是相同的,所以传统的应用程序不会中断。编译器只需将属于该类的新方法放入运行时,并使用与原始代码相同的签名重写方法。

      一个例子:

      您有一个类bing,它输出到终端,但不输出到串行端口,现在这就是您需要的。(出于某种原因)。你有Bing.h和Libbing.so,但包里没有Bing.m。

      Bing类在内部做各种各样的事情,你甚至不知道所有的事情,你只是在头中有公共API。

      你很聪明,所以你为必应类创建了一个(serialoutput)类别。

      [Bing_SerialOutput.m]
      @interface Bing (SerialOutput)   // a category
      - (void)ToSerial: (SerialPort*) port ;
      @end
      
      @implementation Bing (SerialOutput)
      - (void)ToSerial: (SerialPort*) port 
      {
      ... /// serial output code ///
      }
      @end
      

      编译器必须创建一个可以与应用程序链接的对象,运行时现在知道Bing对@selector(ToSerial:)作出响应,您可以像使用该方法生成Bing类一样使用它。不能只添加数据成员方法,这并不是为了创建附加到基类的代码的巨大肿瘤,但它确实比严格类型化语言有其优势。

        5
  •  3
  •   serge-k user3881658    9 年前

    我认为其中一些答案至少指向这样一个观点:继承是向现有类添加功能的一种更重的方式,而类别则更轻。

    当您创建一个新的类层次结构(所有的钟声和哨声)时,就使用继承,当您选择继承作为向现有类添加功能的方法时,可以说继承带来了大量的工作。

    就像这里其他人说的…如果您正在使用继承向nsstring添加一个新的方法,那么您必须转到要使用这个新方法的任何其他代码中,并更改正在使用的类型。但是,如果您使用类别,则可以简单地对现有nsstring类型调用该方法,而不必进行子类化。

    两者都可以达到相同的目的,但是类别似乎给了我们一个更简单的选择,并且需要更少的维护(可能)。

    有人知道在某些情况下类别是绝对必要的吗?

        6
  •  2
  •   mahboudz    15 年前

    一个类别就像一个混合:Ruby中的一个模块,或者有点像Java中的一个接口。你可以把它看作是“赤裸裸的方法”。当您添加类别时,您正在向类中添加方法。维基百科的文章 good stuff .

        7
  •  0
  •   Avik Roy    12 年前

    观察这种差异的最佳方法是: 1。继承:当你想把它完全按照你的方式。 示例:AsyncImageView以实现延迟加载。这是通过继承uiview完成的。 2。类别:只想给它添加一种额外的味道。 示例:我们要替换textfield文本中的所有空格

       @interface UITextField(setText)
          - (NSString *)replaceEscape;
       @end
    
       @implementation UITextField(setText)
          - (NSString *)replaceEscape
          {
             self.text=[self.text stringByTrimmingCharactersInSet:
                               [NSCharacterSet whitespaceCharacterSet]];
             return self.text;
          }
       @end
    

    ---它将为textfield添加一个新的属性,供您转义所有空格。就像在不完全改变其方式的情况下向其添加新维度一样。