abstractに似てる?interfaceとabstractの違いの話

プログラミングC# 第6版 4.10


interfaceの話がでてきました。これは一見するとabstractに非常によく似ています。

using System;

// インターフェイス
interface IClass {
    // 派生側でFooを実装することを強制する
    void Foo ();
}

class CClass : IClass {
    public void Foo () {
        Console.WriteLine("CClass.Foo");
    }
}

class Program {
    static void Main () {
        CClass cobj = new CClass();
        cobj.Foo();
    }
}
$ main
CClass.Foo

これだけだとabstractとほとんど変わりませんね。

では違いを一つずつ見ていきます。

まずinterfaceでメソッドを定義する場合、アクセス修飾子が必要ないようです。

そして派生クラス側でもoverrideが必要ありません。

次に、interfaceではメソッドの定義を持つことができません。

using System;

interface IClass {
    void Foo () {
        Console.WriteLine("CClass.Foo");
    }
}
$ csc main.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.

main.cs(4,7): error CS0531: 'IClass.Foo()': インターフェイス メンバーを定義することはできません。

abstractの場合はメソッドの定義を持つことができるのでこれは大きな違いですね。

またメソッドだけでなく、フィールドも持つことができません。

interface IClass {
    int foo;
}
$ csc main.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.

main.cs(4,6): error CS0525: インターフェイスにフィールドを含めることはできません。

ただしプロパティは持てます。

using System;

interface IClass {
    // プロパティはOK
    int foo {
        get;
        set;
    }
}

class CClass : IClass {
    public int foo {
        get;
        set;
    }
}

class Program {
    static void Main () {
        CClass cobj = new CClass();
    }
}

これだけだとinterfaceとは定義を持つことができない劣化abstractということになりそうなんですが、abstractに無い利点もあります。

それが多重継承が可能という点です。

using System;

interface IClass1 {
    int foo {
        get;
        set;
    }
}

interface IClass2 {
    void Foo ();
}

// 多重継承が可能
class CClass : IClass1, IClass2 {
    public int foo {
        get;
        set;
    }
    public void Foo () {
        Console.WriteLine("CClass.Foo");
    }
}

class Program {
    static void Main () {
        CClass cobj = new CClass();
        cobj.Foo();
    }
}

ということでinterfaceとabstractで色々違いがあるのでそれぞれの利点をちゃんと理解して使いたいと思います。