簡體   English   中英

Array中抽象類的派生類

[英]Derived classes of abstract class in an Array

今天是個好日子。

我有一個關於制作和使用某些基本抽象類的派生類的問題。

我不太明白它是如何工作的。

我的目標:創建一個基本類,定義應該有哪些函數,然后創建不同的派生類。 然后創建一個基類數組並在其中實例化不同的派生類。

例如:

abstract class UIElement
{
    //constructor
    abstract public UIElement();
    //draw element
    abstract public void Draw(int mouseX, int mouseY);
    //checks if the element is pointed at by mouse
    abstract public Boolean IsPointed(int mouseX, int mouseY);
    //defines what happens when clicked
    abstract public void Click(int mouseX, int mouseY);
    //destructor
    abstract public ~UIElement();
}

然后創建幾個派生類,並執行以下操作:

UIElement[] qwe = new UIElement[3];
qwe[0] = new UIElementButton();
qwe[1] = new UIElementLabel();
qwe[2] = new UIElementSomethingElse();

1)這樣做的正確方法是什么,因為我無法找到明確的答案或一篇可以解釋它的文章......

2)關於類變量,應該聲明它們:基類還是派生?

3)如果不同的派生類有不同的變量,應該如何解決該怎么辦?

4)派生類可以有不同的構造函數,包括不同的參數嗎?

在下面的評論中,提問者正在尋找有關使用抽象類編寫繼承層次結構的最佳實踐的建議

從一般的最佳實踐和正確的角度來看,你應該在構造函數中沒有抽象而沒有終結器的情況下聲明你的UIElement基類。 例如

public abstract class UIElement
{
    //constructor
    protected UIElement();
    //draw element
    public abstract void Draw(int mouseX, int mouseY);
    //checks if the element is pointed at by mouse
    public abstract bool IsPointed(int mouseX, int mouseY);
    //defines what happens when clicked
    public abstract void Click(int mouseX, int mouseY);
}

然后,您可以按如下方式實現派生類

public class UIElementButton : UIElement
{
    // Optional - create parameterless constructor and
    // explicitly call base constructor
    public UIElementButton() : base()
    {
    } 

    // Mandatory - must override abstract methods
    public override Draw(int mouseX, int mouseY)
    {
    }

    // Mandatory - must override abstract methods
    public override Boolean IsPointed(int mouseX, int mouseY)
    {
    }

    // Mandatory - must override abstract methods
    public override void Click(int mouseX, int mouseY)
    {
    }
}

您是正確的,如果您按照上面的定義派生類,您可以實例化元素並存儲在基類型的數組中,如下所示:

UIElement[] qwe = new UIElement[3]; 
qwe[0] = new UIElementButton(); 
qwe[1] = new UIElementLabel(); 
qwe[2] = new UIElementSomethingElse(); 

qwe[0].Click(1, 2); // Invokes UIElementButton.Click
qwe[1].Draw(3, 4);  // Invokes UIElementLabel.Draw

您還應該知道WPF中定義了一個UIElement類。 如果為類型定義命名空間,這不會成為問題,但可能會考慮使用更明確的類型名稱(如BaseElement來區分自定義類型。


關於您在評論中的查詢:

有關抽象類使用的進一步建議,請參閱所有關於抽象類 - Codeproject - 應該在哪里聲明類變量:基類還是派生? - 如果不同的派生類有不同的變量,應該如何解決? - 派生類可以有不同的構造函數,包括不同的參數嗎?

這些確實是關於谷歌的不同問題或自己研究的主題,但作為首發,我可以說:

  1. 類變量應在需要它們的范圍內聲明。 這意味着如果你有一個變量Guid _uiElementId並希望它被派生類型訪問,那么它應該在基類中聲明並標記為protected 如果UIElementButton中有一個名為Point _mousePoint的變量,只有UIElement按鈕需要它,請將其留在那里並標記為private

  2. 沒關系 - 任何類型都可以從基類中看到自己的私有變量和受保護的變量。 只要確保名稱不會發生沖突

  3. 是的,他們可以,例如。


 public class UIElementButton : UIElement    
 {    
    private string _buttonText; 

    // Overloaded ctor
    public UIElementButton(string buttonText) : base()
    {
        buttonText = buttonText;
    } 

    // Default constructor. Mark as private or protected 
    // to hide from external API
    public UIElementButton() : base()
    {
    } 
}

最好的祝福,

如果我猜對了,OP來自C ++背景。 C ++和C#之間有許多相似之處,但並非所有功能都匹配1:1。

如果你希望你的“基類”只為所有后代設置有效的操作,即它沒有代碼,你應該使用一個接口:

public interface IUIElement
{
  //draw element
  void Draw(int mouseX, int mouseY);
  //checks if the element is pointed at by mouse
  bool IsPointed(int mouseX, int mouseY);
  //defines what happens when clicked
  void Click(int mouseX, int mouseY);
}

不需要構造函數或析構函數,也不需要將方法顯式聲明為public,因為接口不能包含私有方法/屬性,而是延遲到實現它的類。

在此之后,您可以聲明您的類(Visual Studio可以為您存根):

public class UIElementButton : IUIElement
{
  public UIElementButton()
  {
     ...
  }

  void Draw(int mouseX, int mouseY)
  {
     ...
  }

  bool IsPointed(int mouseX, int mouseY)
  {
     ...
  }

  void Click(int mouseX, int mouseY)
  {
  }
}

你的其余代碼(使用數組)看起來很好,但是,我更喜歡列表而不是數組:

List<IUIElement> qwe = new List<IUIElement>();
qwe.Add(new UIElementButton());
qwe.Add(new UIElementLabel());
qwe.Add(new UIElementSomethingElse());

// some sample usages
foreach(IUIElement element in qwe)
{
   element.Click();
}

qwe[0].Click() //invokes UIElementButton.Click();

//gets all pointed elements
var pointedElements = qwe.Where(e => e.IsPointed(x,y));

從你的問題不清楚這是問題,但你的代碼將無法編譯。 在C#中,您不能擁有abstract構造函數。 終結者既不public也不abstract 沒有任何一個,你可以簡單地刪除它們。

除非你想要處理一些非托管資源,否則你可能不應該使用終結器。 如果你需要,你很可能也想實現IDisposable

暫無
暫無

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

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