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

在C中实现多态性,如何最好地做到这一点?

  •  3
  • Terry_Brown  · 技术社区  · 17 年前

    第一个问题,所以希望你们能对我温柔一点!

    在过去的几天里,我已经阅读了大量关于多态性的文章,并试图将其应用到我在C中所做的工作中,而且似乎有几种不同的实现方法。我希望我能处理好这件事,但即使我没有澄清,我也会很高兴的。

    据我所见,我有3个选择:

    1. 我只能从一个基地继承 类并使用关键字 ’ virtual “在任何方法上, 希望我的派生类 重写。
    2. 我可以用虚拟方法实现一个抽象类 这样做,
    3. 我可以使用接口吗?

    从我所看到的,如果我不需要在基中使用任何实现逻辑,那么一个接口给了我最大的灵活性(因为我不限制自己进行多重继承等),但是如果我要求基能够在派生类所做的任何事情之上做些事情,那么使用1或2是最好的选择。解决方案?

    感谢大家对我的评价-这个周末我在这个网站和其他地方读了很多,而且我 认为 我现在理解这些方法,但是我只想用一种特定语言的方式来澄清我是否在正确的轨道上。希望我也正确地标记了这个。

    干杯, 特里

    6 回复  |  直到 17 年前
        1
  •  6
  •   Marc Gravell    17 年前

    一个接口提供了最抽象的概念;您没有绑定到任何特定的实现(如果由于其他原因,实现必须有一个不同的基类,那么这很有用)。

    对于真正的多态性, virtual 是必须的;多态性通常与类型子类化有关…

    当然,你可以把这两个混合起来:

    public interface IFoo {
        void Bar();
    }
    class Foo : IFoo {
        public virtual void Bar() {...}
    }
    class Foo2 : Foo {
        public override ...
    } 
    

    abstract 是一个独立的问题;选择 摘要 是真的:它能被基类合理地定义吗?如果没有默认实现,则必须 摘要 .

    当有许多常见的实现细节时,公共基类是有用的,纯粹通过接口复制是毫无意义的;但有趣的是,如果实现将 从未 根据实现的不同,扩展方法提供了一种在 interface (这样每个实现就不必这样做了):

    public interface IFoo {
        void Bar();
    }
    public static class FooExtensions {
        // just a silly example...
        public static bool TryBar(this IFoo foo) {
            try {
                 foo.Bar();
                 return true;
            } catch {
                 return false;
            }
        }
    }
    
        2
  •  2
  •   abelenky    17 年前

    以上三项都是有效的,并且都是有用的。 没有“最好”的技巧。只有编程实践和经验才能帮助您在正确的时间选择正确的技术。

    所以,选择一个现在看来合适的方法,然后实现。 注意什么有效,什么失败,吸取教训,然后再试一次。

        3
  •  2
  •   Yann Schwartz    17 年前

    由于以下几个原因,通常倾向于使用接口:

    • 多态性与契约有关,继承与重用有关。
    • 继承链很难正确处理(尤其是对于单一继承,请参见Windows窗体控件中的设计错误,其中可滚动性、富文本等功能已硬编码在继承链中)
    • 继承导致维护问题

    也就是说,如果您想利用公共函数,您可以使用多态性接口(让您的方法接受接口),但是使用抽象基类来共享一些行为。

    public interface IFoo
    {
        void Bar();
        enter code here
    }
    

    将是您的界面

    public abstract class BaseFoo : IFoo
    {
        void Bar
      {
            // Default implementation
      }
    }
    

    将是您的默认实现

    public class SomeFoo : BaseFoo
    {
    
    }
    

    是一个重用实现的类。

    不过,您将使用接口来实现多态性:

    public class Bar
    {
       int DoSometingWithFoo(IFoo foo)
    {
    
        foo.Bar();
    }
    }
    

    注意,我们在方法中使用的是接口。

        4
  •  1
  •   fortran    17 年前

    您应该问的第一件事是“为什么我需要使用多态性?”因为多态性本身并不是结束的,而是达到目的的一种手段。一旦你的问题定义好了,就应该更清楚地使用哪种方法。

    不管怎样,您所评论的这三个问题并不是独占的,如果您只需要在一些类之间重用逻辑,而不需要在其他类之间重用逻辑,或者需要一些不同的接口,那么您仍然可以将它们混合在一起…

        5
  •  1
  •   abhilash    17 年前
    • 使用抽象类来强制类结构
    • 使用接口描述行为
        6
  •  0
  •   ChrisBD    17 年前

    它实际上取决于你想要如何构造你的代码以及你想要用它做什么。

    从测试的角度来看,拥有一个类型为interface的基类是很好的,因为您可以使用模拟对象来替换它。

    如果您希望在某些函数中实现代码,而不是在其他函数中实现代码,那么抽象类实际上就是一个接口,就像抽象类除了抽象函数之外没有其他任何东西一样。

    记住,抽象类不能被实例化,因此对于工作代码,必须有一个派生自它的类。

    实际上,一切都是有效的。

    如果我有很多类是从抽象类派生的,但是在一个较浅的层次上(比如只有一个类向下),我倾向于使用抽象类。

    如果我期望有一个深层次的继承,那么我将使用一个带有虚拟函数的类。

    因此,最好保持类的简单性,以及它们的继承性,因为它们越复杂,就越有可能引入bug。