主な違いは、基本クラスをインスタンス化できるのに対し、コンパイラは抽象クラスをインスタンス化できないことです (これは意味がないかもしれません)。
AbstractType a = new AbstractType(); //compiler error
AbstractType d = new DerivedType(); //OK
BaseType b = new BaseType(); //OK
変数d
を使用すると、抽象メソッドがオーバーライドされていることが保証されます (そうしないと、DerivedType
クラスにコンパイラ エラーが発生します)。
あなたはまだ多くの混乱についてコメントしているので、私が実際にこの概念をクリックした例を挙げます。タワー ディフェンス ゲームを作成しているとします。タワー クラスがあり、すべてのタワーには攻撃する能力があるため、次のような抽象タワー クラスを作成します。
abstract class Tower
{
abstract void Attack();
}
これで、いくつかのタワー クラスを作成できます。
class FlameTower : Tower
{
override void Attack()
{
//Shoot flames at everyone
}
}
class IceTower : Tower
{
override void Attack()
{
//Shoot ice everywhere
}
}
タワーのリストを宣言する場合は、次のように記述できます。
List<Tower> towerList = new List<Tower>();
towerList.Add(new FireTower());
towerList.Add(new IceTower());
次に、それらを繰り返して、すべての攻撃を行います。
foreach (Tower t in towerList)
{
t.Attack();
}
また、すべてのクラスは抽象としてマークされているため、攻撃を実装していることが保証されており、実装していない場合はコンパイル エラーになります。基本クラスがこれを許可する場合を除いて、これはすべて基本クラスで実行できます。
towerList.Add(new Tower());
これで attack を呼び出そうとするとnew Tower()
、空の抽象メソッドにヒットしますが、これは私たちが望んでいるものではありません。したがって、何かをジェネリック タワーとして宣言することを禁止するために、クラスを抽象化します。そうすれば、すべてが独自の定義をAttack
持ち、何かを実行することがわかります。