簡體   English   中英

C#中抽象類的構造函數

[英]Constructor of an abstract class in C#

為什么可以在 C# 中為抽象類編寫構造函數?
據我所知,我們不能實例化一個抽象類.. 那它有什么用呢?
你不能實例化這個類,對吧?

因為您可能希望在抽象類中實例化數據的標准方式。 這樣,您可以讓從該類繼承的類調用基本構造函數。

public abstract class A{

    private string data;

    protected A(string myString){
      data = myString;
    }

}

public class B : A {

     B(string myString) : base(myString){}

}

據我所知,我們無法實例化抽象類

你的錯誤就在那里。 當然你可以實例化一個抽象類。

abstract class Animal {}
class Giraffe : Animal {}
...
Animal animal = new Giraffe();

那里有一個 Animal 的實例。 您通過創建一個派生自抽象類的具體類並實例化它來實例化一個抽象類。 請記住,派生具體類的實例也是其抽象基類的實例。 即使 Animal 是抽象的,Giraffe 的實例也是 Animal 的實例。

鑒於您可以實例化一個抽象類,它需要像任何其他類一樣具有構造函數,以確保滿足其不變量。

現在,靜態類是您實際上無法實例化的類,您會注意到在靜態類中創建實例構造函數是不合法的。

這是一種強制執行抽象類的一組不變量的方法。 也就是說,無論子類做什么,您都希望確保基類的某些事情總是正確的......例如:

abstract class Foo
{
    public DateTime TimeCreated {get; private set;}

    protected Foo()
    {
         this.TimeCreated = DateTime.Now;
    }
}

abstract class Bar : Foo
{
    public Bar() : base() //Bar's constructor's must call Foo's parameterless constructor.
    { }
}

不要將構造函數視為new運算符的對偶。 構造函數的唯一目的是確保您在開始使用之前擁有處於有效狀態的對象。 恰好是我們通常通過new運算符調用它。

它可以強制執行抽象類的所有實現或您在抽象類上實現的任何方法所需的一些初始化邏輯(並非抽象類上的所有方法都必須是抽象的,有些可以實現)。

從抽象基類繼承的任何類都必須調用基構造函數。

抽象類的要點

  1. 抽象類不能被實例化。
  2. 抽象類可以有構造函數和析構函數。
  3. 抽象類不能是密封類,因為密封修飾符防止類被繼承。
  4. 抽象類包含抽象和非抽象成員。
  5. 抽象類成員可以是私有的、受保護的和內部的。
  6. 抽象成員不能有私有訪問修飾符。
  7. 抽象成員是隱式虛擬的,必須由非抽象派生類實現。

添加到上述答案和示例。

是的,一個抽象類可以有一個構造函數,即使一個抽象類不能被實例化。 將解釋一個抽象類構造函數 c# 代碼示例。 但是,也可能會出現下一個問題,好像我們不能實例化(使用 new 構造對象)抽象類,那么抽象類中的構造函數是什么,或者為什么要在抽象類中使用構造函數?

請注意,當我們創建派生類的對象時,會隱式調用抽象基類的構造函數,即使我們無法實例化抽象類。 例如在程序中,如果我們創建一個派生類的對象,那么抽象基類的構造函數也會被調用。

這也是例子之一

例子

abstract class A
{
    protected A() {Console.WriteLine("Abstract class constructor"); }
}
//Derived class
class B : A
{
   public B() {Console.WriteLine("Derived class constructor"); }
}

class Program
{
    static void Main(string[] args)
    {
        B obj = new B();
    }
}

輸出將是

Abstract class constructor
Derived class constructor

抽象類不能直接實例化。 抽象類構造函數從派生類執行。 因此,最好將受保護的訪問修飾符與抽象類構造函數一起使用。 公開沒有意義

抽象類構造函數也可用於執行與每個子類相關的代碼。

這可以防止重復代碼。

通常構造函數涉及初始化正在創建的對象的成員。 在繼承的概念中,通常繼承層次結構中的每個類構造函數都負責實例化自己的成員變量。 這是有道理的,因為必須在定義變量的地方進行實例化。

由於抽象類不是完全抽象的(與接口不同),它是抽象和具體成員的混合體,非抽象的成員需要初始化,這是在抽象類的構造函數中完成的,因此必須有構造函數在抽象類中。 當然,抽象類的構造函數只能從派生類的構造函數中調用。

你是絕對正確的。 我們不能實例化一個抽象類,因為抽象方法沒有任何主體,即抽象方法不可能實現。 但是可能有一些場景需要初始化基類的一些變量。 您可以按照@Rodrick 的建議使用base關鍵字來做到這一點。 在這種情況下,我們需要在抽象類中使用構造函數。

我也想在抽象的表面上做一些閃耀所有的答案幾乎涵蓋了所有的東西。 還是我的 2 美分

抽象類是普通類,但有一些例外

  1. 您該類的任何客戶/消費者都無法創建該類的對象,這絕不意味着它的構造函數永遠不會調用。 它的派生類可以選擇調用哪個構造函數。(如一些答案所示)
  2. 它可能具有抽象功能。

在可繼承的具體類Thing中定義具有公共或內部存儲類的構造函數有效地定義了兩種方法:

  • 作用於this的方法(我稱之為InitializeThing )沒有返回值,並且只能從ThingCreateThingInitializeThing方法以及子類的InitializeXXX方法調用。

  • 一個方法(我稱之為CreateThing ),它返回構造函數指定類型的對象,本質上表現為:

     Thing CreateThing(int whatever) { Thing result = AllocateObject<Thing>(); Thing.initializeThing(whatever); }

抽象類有效地創建了僅第一種形式的方法。 從概念上講,上面描述的兩個“方法”沒有理由需要具有相同的訪問說明符。 然而,在實踐中,沒有辦法以不同的方式指定它們的可訪問性。 請注意,就實際實現而言,至少在 .NET 中, CreateThing並沒有真正實現為可調用方法,而是表示插入到newThing = new Thing(23);處的代碼序列。 陳述。

抽象類可以有需要初始化的成員變量,因此可以在抽象類構造函數中初始化它們,並在初始化派生類對象時調用該構造函數。

來自https://msdn.microsoft.com/en-us/library/ms182126.aspx

抽象類型的構造函數只能由派生類型調用。 因為公共構造函數創建類型的實例,而您不能創建抽象類型的實例,所以具有公共構造函數的抽象類型設計不正確。

由於只有派生類可以使用抽象類構造函數,因此如果需要,必須將抽象類構造函數聲明為protected

但是,當在抽象類中聲明公共構造函數時,VS 編譯器不會抱怨(使用默認規則),但是它不允許創建新實例。

您可以在實現所有方法后實例化它。 然后將調用構造函數。

有以下兩個重要特性可以防止繼承 Abstract 類

  1. 抽象類必須有抽象方法,否則不是抽象類

  2. 抽象類必須由派生類繼承,所以如果一個類被其他類繼承,而不是用來創建該類的對象

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM