abstract
修飾子は、その修飾対象の実装が不足しているか、不完全であることを示します。 クラスやメソッド、プロパティ、インデクサー、イベントと組み合わせて abstract 修飾子を使用することができます。 クラス宣言に abstract
修飾子を使用して、クラスは他のクラスの基底クラスとしてのみ使用することを意図し、それ自体ではインスタンス化されないことを示します。 abstract としてマークされたメンバーは、その抽象クラスから派生した非抽象クラスによって実装される必要があります。
抽象クラスには、抽象メンバー (実装がなく、派生クラスでオーバーライドする必要があります) と完全に実装されたメンバー (通常のメソッド、プロパティ、コンストラクターなど) の両方を含めることができます。 これにより、抽象クラスは共通の機能を提供しながら、派生クラスで特定の抽象メンバーを実装する必要があります。
例 1 - メンバーが混在する抽象クラス
次の例は、実装されたメソッドと抽象メンバーの両方を含む抽象クラスを示しています。
namespace LanguageKeywords;
public abstract class Vehicle
{
protected string _brand;
// Constructor - implemented method in abstract class
public Vehicle(string brand) => _brand = brand;
// Implemented method - provides functionality that all vehicles share
public string GetInfo() => $"This is a {_brand} vehicle.";
// Another implemented method
public virtual void StartEngine() => Console.WriteLine($"{_brand} engine is starting...");
// Abstract method - must be implemented by derived classes
public abstract void Move();
// Abstract property - must be implemented by derived classes
public abstract int MaxSpeed { get; }
}
public class Car : Vehicle
{
public Car(string brand) : base(brand) { }
// Implementation of abstract method
public override void Move() => Console.WriteLine($"{_brand} car is driving on the road.");
// Implementation of abstract property
public override int MaxSpeed => 200;
}
public class Boat : Vehicle
{
public Boat(string brand) : base(brand) { }
// Implementation of abstract method
public override void Move() => Console.WriteLine($"{_brand} boat is sailing on the water.");
// Implementation of abstract property
public override int MaxSpeed => 50;
}
public class AbstractExample
{
public static void Examples()
{
// Cannot instantiate abstract class: Vehicle v = new Vehicle("Generic"); // Error!
Car car = new Car("Toyota");
Boat boat = new Boat("Yamaha");
// Using implemented methods from abstract class
Console.WriteLine(car.GetInfo());
car.StartEngine();
// Using abstract methods implemented in derived class
car.Move();
Console.WriteLine($"Max speed: {car.MaxSpeed} km/h");
Console.WriteLine();
Console.WriteLine(boat.GetInfo());
boat.StartEngine();
boat.Move();
Console.WriteLine($"Max speed: {boat.MaxSpeed} km/h");
}
}
class Program
{
static void Main()
{
AbstractExample.Examples();
}
}
/* Output:
This is a Toyota vehicle.
Toyota engine is starting...
Toyota car is driving on the road.
Max speed: 200 km/h
This is a Yamaha vehicle.
Yamaha engine is starting...
Yamaha boat is sailing on the water.
Max speed: 50 km/h
*/
この例では、 Vehicle
抽象クラスは次を提供します。
-
実装されたメンバー:
GetInfo()
メソッド、StartEngine()
メソッド、コンストラクター- これらは、すべての車両に共通の機能を提供します。 -
抽象メンバー:
Move()
メソッドとMaxSpeed
プロパティ - これらは、各車両の種類によって実装する必要があります。
この設計により、抽象クラスは共有機能を提供しながら、派生クラスで車両固有の動作を実装できます。
例 2
この例で、Square
の機能は、GetArea
から派生している Shape
クラスで実装する必要があります。
abstract class Shape
{
public abstract int GetArea();
}
class Square : Shape
{
private int _side;
public Square(int n) => _side = n;
// GetArea method is required to avoid a compile-time error.
public override int GetArea() => _side * _side;
static void Main()
{
var sq = new Square(12);
Console.WriteLine($"Area of the square = {sq.GetArea()}");
}
}
// Output: Area of the square = 144
抽象クラスには次の特徴があります。
抽象クラスはインスタンス化できません。
抽象クラスには抽象メソッドとアクセサーを記述することができます。
抽象クラスには、実装されたメソッド、プロパティ、フィールド、および派生クラスに機能を提供するその他のメンバーを含めることもできます。
sealed 修飾子を使って抽象クラスを修飾することはできません。2 つの修飾子が逆の意味を持つためです。
sealed
修飾子を指定したクラスは継承が禁止されるのに対し、abstract
修飾子を指定したクラスは継承による使用が強制されます。抽象クラスから派生した具象クラスには、継承されたすべての抽象メソッドとアクセサーの実際の機能を実装する必要があります。
メソッドまたはプロパティに機能が実装されていないことを示すには、そのメソッドまたはプロパティの宣言で abstract
修飾子を使います。
抽象メソッドには次の特徴があります。
抽象メソッドは、仮想メソッドの性質を暗に含んでいます。
抽象メソッドの宣言は、抽象クラスでしか認められません。
抽象メソッドの宣言には実際の機能が実装されないため、メソッドの本体はありません。つまり、メソッドの宣言は、末尾のセミコロンがあるだけで、シグネチャの後ろに中かっこ ({ }) は存在しません。 次に例を示します。
public abstract void MyMethod();
実際の機能は、メソッド (具象クラスのメンバー) に override を指定して実装します。
抽象プロパティは、宣言と呼び出しの構文の違いを除けば、抽象メソッドと似た働きを持ちます。
abstract
修飾子を静的プロパティに対して使うのは誤りです。継承する抽象プロパティは、派生クラス内で override 修飾子を使ったプロパティ宣言を記述することでオーバーライドすることができます。
抽象クラスの詳細については、「抽象クラスとシール クラス、およびクラス メンバー」を参照してください。
すべてのインターフェイス メンバーの機能は、抽象クラスで実装する必要があります。
インターフェイスを実装する抽象クラスで、インターフェイス メソッドを抽象メソッドにマップすることもできます。 次に例を示します。
interface I
{
void M();
}
abstract class C : I
{
public abstract void M();
}
例 3
この例の DerivedClass
クラスは、抽象クラス BaseClass
から派生しています。 この抽象クラスには、AbstractMethod
という抽象メソッドのほか、X
と Y
の 2 つの抽象プロパティが存在します。
// Abstract class
abstract class BaseClass
{
protected int _x = 100;
protected int _y = 150;
// Abstract method
public abstract void AbstractMethod();
// Abstract properties
public abstract int X { get; }
public abstract int Y { get; }
}
class DerivedClass : BaseClass
{
public override void AbstractMethod()
{
_x++;
_y++;
}
public override int X // overriding property
{
get
{
return _x + 10;
}
}
public override int Y // overriding property
{
get
{
return _y + 10;
}
}
static void Main()
{
var o = new DerivedClass();
o.AbstractMethod();
Console.WriteLine($"x = {o.X}, y = {o.Y}");
}
}
// Output: x = 111, y = 161
この例の抽象クラスを次のようなステートメントでインスタンス化しようとするとどうなるかを次に示します。
BaseClass bc = new BaseClass(); // Error
このように、抽象クラス 'BaseClass' のインスタンスをコンパイラが作成できないことを伝えるエラーが発生します。
ただし、次の例のように、抽象クラス コンストラクターを使用できます。
例 4
public abstract class Shape
{
public string Color { get; set; }
// Constructor of the abstract class
protected Shape(string color)
{
Color = color;
Console.WriteLine($"Created a shape with color {color}.");
}
// Abstract method that must be implemented by derived classes
public abstract double CalculateArea();
}
public class Square : Shape
{
public double Side { get; set; }
// Constructor of the derived class calling the base class constructor
public Square(string color, double side) : base(color)
{
Side = side;
}
public override double CalculateArea()
{
return Side * Side;
}
}
public class Program
{
public static void Main(string[] args)
{
Square square = new Square("red", 5);
Console.WriteLine($"Area of the square: {square.CalculateArea()}");
}
}
Shape
クラスは abstract
宣言されています。つまり、直接インスタンス化することはできません。 代わりに、他のクラスのブループリントとして機能します。
- 抽象クラスのオブジェクトを作成することはできませんが、コンストラクターを持つことができます。 通常、このコンストラクターは
protected
です。つまり、派生クラスからのみアクセスできます。 この場合、Shape
コンストラクターはcolor
パラメーターを受け取り、Color
プロパティを初期化します。 また、コンソールにメッセージを出力します。public Square(string color, double side) : base(color)
部分は基底クラスのコンストラクター (Shape
) を呼び出し、color
引数を渡します。 - Shape クラスでは、定義されたコンストラクターは、
protected Shape(string color)
パラメーターとして色を受け取ります。 つまり、C# によって自動的に提供される既定のパラメーターなしのコンストラクターがなくなったため、派生クラスは基本コンストラクターを呼び出すために: base(color)
式を使用する必要があります。 既定値を色protected Shape(string color="green")
に設定すると、派生クラスの: base(color)
式を省略できますが、このようなコンストラクターprotected Shape(string color="green")
が呼び出され、色が緑色に設定されます。
C# 言語仕様
詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。
関連項目
.NET