2010-08-16 32 views
0

我在C#中有一些關於繼承的基本問題。在c#中的繼承問題

我有兩個類。我希望子類繼承基類的所有成員(例如x和y),但它似乎使用繼承,我應該初始化基構造函數。如果我在子類中定義另一個x和y,以便我稍後初始化基構造函數,那麼繼承的用法是什麼?什麼是解決方案?

另一個問題是,我有兩個方法在基類和子類中具有相同的簽名,我需要同時使用這兩個方法。我能做什麼?

class Base 
{ 
    int x; 
    int y; 
    string name; 

    public Base(int i,int j) 
    { 
     x = i; 
     y = j; 
     name="s"; 
    } 
} 

class Child 
{ 
    public Base() 
    { 

    } 
} 

回答

2

你的問題不是很清楚,代碼也是無效的[現在由編輯修改],但我會回答我認爲你問的問題。

要在派生類中初始化基類的領域,你必須從你的派生類的構造函數調用基類的構造:

class Base 
{ 
    private int x; 
    private int y; 

    // ... 

    public Base(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 
} 

// option 1, pass in values as parameters to constructor: 
class Child1 
{ 
    public Child(int x, int y) 
     : base(x, y) // this passes the values up to the base constructor 
    { 
    } 
} 

// option 2, pass literals to the base constructor: 
class Child2 
{ 
    public Child() 
     : base(3, 4) // this passes the literal values 3 and 4 to the base constructor 
    { 
    } 
} 

// elsewhere 

var child1 = new Child1(1, 2); // child1.x = 1, child1.y = 2 
var child2 = new Child2(); // child2.x = 3, child2.y = 4 

現在,關於您對派生有方法的第二個問題類同名。

class Base 
{ 
    public virtual void SomeAction() 
    { 
     Console.Out.WriteLine("Base.SomeAction"); 
    } 

    public void DifferentAction() 
    { 
     Console.Out.WriteLine("Base.DifferentAction"); 
    } 
} 

class Derived 
{ 
    // this is a normal override 
    public override void SomeAction() 
    { 
     Console.Out.WriteLine("Derivde.SomeAction"); 
    } 

    // this is an advanced technique which you should try to avoid in most cases 
    public new void DifferentAcion() 
    { 
     Console.Out.WriteLine("Derived.DifferentAction"); 
    } 
} 

// elsewhere 
var base = new Base(); 
base.SomeAction(); // prints Base.SomeAction 
base.DifferentAction(); // prints Base.DifferentAction 

var derived = new Derived(); 
derived.SomeAction(); // prints Derived.SomeAction 
derived.DifferentAction(); // prints Derived.DifferentAction 

((Base) derived).SomeAction(); // prints Derived.SomeAction 
((Base) derived).DifferentAction(); // prints Base.DifferentAction 

如果:如果你要重新定義一個方法的行爲,你應該讓基類虛擬和在派生類中,你可以從方法看覆蓋它在這個例子叫SomeAction方法被重寫,那麼無論您將其引用爲基本類型還是派生類型,都會展示新行爲。 (如果使用new關鍵字,或者不要放任何東西,那麼會創建一個新的繼承鏈,其行爲將取決於您是將該對象引用爲基類型還是派生類型,您可以看到這個在上面代碼中的最後兩個調用中:對於重寫方法,使用派生行爲,但對於使用「新」的方法,當對象被視爲Base時顯示原始行爲。)

0

使用繼承的主要原因是,您可能有許多類,它們具有與超類基本相同的功能。通過使它們成爲超類的子類,您可以將字段和方法放在超類中,然後由所有子類繼承,從而允許您只寫一次這樣的方法和字段,而不是像您一樣多次有子類。

0

不要在子類中定義x和y。如果Child從Base繼承,它們已經在那裏。

0

類構造函數是總是在您實例化派生類時調用。如果基類有一個默認的構造函數,如果你省略了對基類構造函數的顯式調用,這將會被調用。

E.g.

class Base 
{ 
    int x; 
    int y; 

    //default constructor 
    public Base() 
    { 
    x = -1; 
    y = -1; 
    } 

    public Base(int x, int y) 
    { 
    this.x = x; 
    this.y = y; 
    } 
} 

class Derived 
{ 
    public Derived() 
    { 
    } 
} 

當Derived對象被創建時,這將編譯和設置派生的實例字段爲-1。 但是,如果你省略了默認的構造函數,你會得到一個像你所描述的編譯錯誤。現在,編譯器無法自動生成對基礎構造函數的調用。我想知道哪些參數與

base(x=??,y=??) 

一般稱呼它,你應該有公共字段/名稱相同的屬性多次聲明,這是幾乎總是一個強大的設計味道。 如果基類具有受保護的內部或公共字段/屬性,派生類也是如此(內部有一些奇怪的情況)。對於方法,您可以隱藏方法的基類實現或覆蓋它。後者是更常見的,並且要求基本定義是抽象的或虛擬的,例如 ,例如如果你

//this requires Base to be declared abstract as well 
public abstract void AbstractMethod(); 
public virtual void VirtualMethod(){} 

,使您如果需要隱藏你能做到的方法,雖然它一般不鼓勵(見下爲什麼)寫入在派生類中

public override void AbstractMethod(){} 
public override void VirtualMethod(){} 

如下 剛重新聲明編譯器會給你一個警告的方法,但你可以用new來告訴編譯器你實際上想要隱藏的方法它看起來像這樣:

public new void SomeHiddenMethod(){}

怎麼過這個地區在使用該類型的對象的(潛在的)休影響

public void SomeMEthod(Derived d) 
{ 
    //this calls the implementation in Derived 
    d.SomeHiddenMethod(); 
    Base b = d; 
    //this calls the implementation in Base 
    b.SomeHiddenMethod(); 
} 

隱藏方法從而使得它非常難推理的代碼,因爲調用同樣的方法對同一對象可能即使對象在兩次調用之間沒有改變狀態,但僅僅是因爲變量的聲明類型發生了更改,結果也會有所不同。

關於繼承的最後一點說明,您應該避免繼承功能,簡而言之,就是因爲您需要兩個(無關的)類中的相同功能,您不應該創建基類來保存該功能,而應該創建第三個類並注入該類的實例(或類似方法),並且在設計一個類的公共接口時,您應該考慮很多有關Liskov substitutional principle的內容。