如何强制子类实现一个方法?

56

我正在创建一个对象结构,并且希望所有基类的子类都被强制实现一个方法。

我能想到的唯一方法是:

  1. 抽象类 - 这样做可行,但基类有一些有用的辅助函数,会被某些子类使用。

  2. 接口 - 如果仅应用于基类,则子类不必实现该函数,只需基类实现即可。

这是否可行?

N.B. 这是一个.NET 2 应用程序。


5
注意,将抽象方法放在抽象类中并不要求子类实现该方法。您可以创建尽可能多的未实现该方法的子类;这些子类只需要同样是抽象类即可。 - Eric Lippert
3
就我所知,正确的面向对象术语应该是“方法”而不是“函数”。 - R. Martinho Fernandes
5个回答

78

你可以在一个有其他已实现方法的类中拥有抽象方法。与接口相比的优势在于,您可以在类中包含一些代码,并强制新对象填写抽象方法的细节。

public abstract class YourClass
{
    // Your class implementation

    public abstract void DoSomething(int x, int y);

    public void DoSomethingElse(int a, string b)
    {
        // You can implement this here
    }
}

请看我对查尔斯回答留下的评论。 - tgandrews
哇,谢谢,这个很好用。我没想到抽象类里面也可以有方法并带有功能。 - tgandrews
抽象方法本身没有功能;功能需要在继承的类中实现。 - Andreas Grech
4
但它们可以拥有其他非抽象方法(以及虚方法、重写的方法,任何普通类都可以拥有的内容)。 - thecoop

16

一个抽象类 - 可以使用,但是基类有一些有用的帮助函数被某些子类使用

一个抽象类并不需要所有提供的函数都是抽象的。

abstract class Base {
    public void Foo() {} // Ordinary method
    public virtual void Bar() {} // Can be overridden
    public abstract void Xyz(); // This one *must* be overridden
}
请注意,如果您将public替换为protected,则标记的方法将仅对基类和子类可见。

3
是的,我没有意识到你可以这样做。我越来越喜欢C#,并且每天都更加喜欢它。 - tgandrews
@Thoku:这不是特定于C#的行为。所有基于类的面向对象语言都表现出这种行为。 - R. Martinho Fernandes

15
一个接口 - 如果仅应用于基类,则子类不必实现函数,只需基类实现即可。这不是完全正确的。如果基类是抽象的,您可以将属于接口的方法标记为抽象,并强制在子类中实现。这带来了一种您没有提到的选项:同时使用两者。您有一个IFoo接口和一个FooBase抽象基类来实现它,或其中的一部分。这为子类提供了接口(或一部分)的“默认”实现,还让您从其他东西继承并实现接口,或者如果您想要实现接口但不继承基类实现它也行。例子可能会有所帮助:
// Your interface
interface IFoo { void A(); void B; }

// A "default" implementation of that interface
abstract class FooBase : IFoo
{
    public abstract void A();

    public void B()
    {
        Console.WriteLine("B");
    }
}

// A class that implements IFoo by reusing FooBase partial implementation
class Foo : FooBase
{
    public override void A()
    {
        Console.WriteLine("A");
    }
}

// This is a different class you may want to inherit from
class Bar
{
    public void C()
    {
        Console.WriteLine("C");
    }
}

// A class that inherits from Bar and implements IFoo
class FooBar : Bar, IFoo
{
    public void A()
    {
        Console.WriteLine("Foobar.A");
    }
    public void B()
    {
        Console.WriteLine("Foobar.B");
    }
}

7
是的,如果您需要为所有需要执行此操作的类逻辑上属于现有抽象基类的子类,则应向基类添加一个抽象方法...这比接口更好,因为它允许您稍后添加实现(通过将抽象基类方法更改为具有默认实现的虚拟方法),如果/当发现,例如,十个派生类中有八个将具有相同的实现,而只有两个不同...
编辑:(根据下面评论中的线程)必须将基类声明为抽象才能执行此操作...您不能在非抽象类中使用抽象方法,因为可以实例化非抽象类,如果创建了其实例,则该方法将没有实现。因此,这是非法的。通过将基类声明为抽象,您抑制了类的实例化。然后,只能实例化非抽象派生类,在其中(因为基本方法是抽象的)必须为该方法添加实现。

编译器在抱怨基类必须是抽象的才能工作。也许这是因为它是.NET 2? - tgandrews
2
@Thoku:这在该语言的所有版本中都会发生。您不能拥有带有抽象方法的具体类。 - R. Martinho Fernandes

2

以下是带参数的完整工作线程示例(.netcore 2.2):

class User{
    public string Name = "Fen";
}

class Message{
    public string Text = "Ho";
}

// Interface
interface IWorkerLoop
{
    // Working with client message
    string MessageWorker(string msg);
}

// AbstractWorkerLoop partial implementation
public abstract class AbstractWorkerLoop : IWorkerLoop
{
    public User user;
    public Message msg;

    // Append session object to loop
    public abstract AbstractWorkerLoop(ref User user, ref Message msg){
        this.user = user;
        this.msg = msg;
    }

    public abstract string MessageWorker(string msg);
}

// Worker class
public class TestWorkerLoop : AbstractWorkerLoop
{
    public TestWorkerLoop(ref User user, ref Message msg) : base(user, msg){
        this.user = user;
        this.msg = msg;
    }

    public override string MessageWorker(string msg){
        // Do something with client message    
        return "Works";
    }
}

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