2010-04-29 57 views
5

構造函數中的代碼是否添加到子類構造函數中的代碼中?或者子類的構造函數是否覆蓋超類?鑑於這個例子父類的構造:構造函數中的代碼是否添加到子類構造函數中的代碼中?

class Car{ 
    function Car(speed:int){ 
      trace("CAR speed "+speed) 
    } 
} 

...這子類構造函數:

class FordCar extends Car{ 
    function FordCar(model:string){ 
      trace("FORD model "+model) 
    } 
} 

當創建的FordCar一個實例,將這個跟蹤「汽車」和「福特」?

編輯:參數是否也加起來?查看上面更新的代碼。

回答

6

是的。在大多數語言中,基類構造函數被執行,然後是子類構造函數。這將追蹤到:「CAR」,然後是「FORD」。

如果構造子類的實例,則兩個類構造函數都應該始終執行。根據所討論的語言,基類構造函數的實際執行和選擇(包括排序)可能會有所不同。 (這是特別真實的語言,允許多重繼承 - 作爲執行的順序可能是難以確定在某些情況下,乍看之下。)


編輯:

在大多數語言中,你的編輯代碼不會編譯。子類通常需要將相同類型的參數傳遞給基類構造函數。這是特定的語言,但往往看起來是這樣的:

function FordCar(model: string) : Car(42) { 

在某些語言(主要是動態語言),語言會嘗試自動進行轉換,但你往往可能仍然需要指定調用哪個父構造函數。

通常情況下,你可以這樣做:

function FordCar(int: speed, model: string) : Car(speed) { 
    trace("FORD model " + model) 
} 
+0

我會永遠跑步嗎?含義? – 2010-04-29 18:57:17

+0

@傑瑞米:我重新錄製了 - 更好? – 2010-04-29 18:58:35

+0

是啊!而且論據也會加起來嗎?請參閱上面我更新的代碼。 – 2010-04-29 19:00:20

4

是的,它會跟蹤兩者。通常你的子類的構造函數將不得不調用你的基類的構造函數。如果給出多個基類構造函數,那麼你可能有選項。但是,如果只給出一個,那麼你必須滿足它的要求。

考慮下面的代碼,並要特別注意的各種構造和他們與父類的構造函數是如何工作的:

public interface IAnimal 
{ 
    string GetName(); 
    string Talk(); 
} 

public abstract class AnimalBase : IAnimal 
{ 
    private string _name; 

    // Constructor #1 
    protected AnimalBase(string name) 
    { 
     _name = name; 
    } 

    // Constructor #2 
    protected AnimalBase(string name, bool isCutsey) 
    { 
     if (isCutsey) 
     { 
      // Change "Fluffy" into "Fluffy-poo" 
      _name = name + "-poo"; 
     } 
    } 

    // GetName implemention from IAnimal. 
    // In C#, "virtual" means "Let the child class override this if it wants to but is not required to" 
    public virtual string GetName() 
    { 
     return _name; 
    } 

    // Talk "implementation" from IAnimal. 
    // In C#, "abstract" means "require our child classes to override this and provide the implementation". 
    // Since our base class forces child classes to provide the implementation, this takes care of the IAnimal implementation requirement. 
    abstract public string Talk(); 
} 

public class Dog : AnimalBase 
{ 
    // This constructor simply passes on the name parameter to the base class's constructor. 
    public Dog(string name) 
     : base(name) 
    { 
    } 

    // This constructor passes on both parameters to the base class's constructor. 
    public Dog(string name, bool isCutsey) 
     : base(name, isCutsey) 
    { 
    } 

    // Override the base class's Talk() function here, and this satisfy's AnimalBase's requirement to provide this implementation for IAnimal. 
    public override string Talk() 
    { 
     return "Woof! Woof!"; 
    } 
} 

public class SmallDog : Dog 
{ 
    private bool _isPurseDog; 

    // This constructor is unique from all of the other constructors. 
    // Rather than the second boolean representing the "isCutsey" property, it's entirely different. 
    // It's entirely a coincidence that they're the same datatype - this is not important. 
    // Notice that we're saying ALL SmallDogs are cutsey by passing a hardcoded true into the base class's (Dog) second parameter of the constructor. 
    public SmallDog(string name, bool isPurseDog) 
     : base(name, true) 
    { 
     _isPurseDog = isPurseDog; 
    } 

    // This tells us if the dog fits in a purse. 
    public bool DoesThisDogFitInAPurse() 
    { 
     return _isPurseDog; 
    } 

    // Rather than using Dog's Talk() implementation, we're changing this because this special type of dog is different. 
    public override string Talk() 
    { 
     return "Yip! Yip!"; 
    } 
} 

public class Chihuahua : SmallDog 
{ 
    private int _hatSize; 

    // We say that Chihuahua's always fit in a purse. Nothing else different about them, though. 
    public Chihuahua(string name, int hatSize) 
     : base(name, true) 
    { 
     _hatSize = hatSize; 
    } 

    // Of course all chihuahuas wear Mexican hats, so let's make sure we know its hat size! 
    public int GetHatSize() 
    { 
     return _hatSize; 
    } 
} 

public class Cat : AnimalBase 
{ 
    // This constructor simply passes on the name parameter to the base class's constructor. 
    public Cat(string name) 
     : base(name) 
    { 
    } 

    // This constructor passes on both parameters to the base class's constructor. 
    public Cat(string name, bool isCutsey) 
     : base(name, isCutsey) 
    { 
    } 

    // Override the base class's Talk() function here, and this satisfy's AnimalBase's requirement to provide this implementation for IAnimal. 
    public override string Talk() 
    { 
     return "Meoooowwww..."; 
    } 
} 

public class Lion : Cat 
{ 
    public Lion(string name) 
     : base(name) 
    { 
    } 

    // Rather than using Cat's Talk() implementation, we're changing this because this special type of cat is different. 
    public override string Talk() 
    { 
     return "ROAR!!!!!!!!"; 
    } 
} 

[編輯]

您添加通常不會

您的代碼編譯。子類的構造函數通常必須提供所有參數給超類的構造函數。不提供它們不是一種選擇。看我的代碼,看看我的子類構造函數是如何爲超類構造函數提供參數的。有時他們只是傳遞參數和其他時間,他們實際上把硬編碼true/false值。

+0

不,當一個子類的實例被創建時,它是否也會在超類中執行代碼? – 2010-04-29 18:56:47

+1

對於構造函數來說,是的,它會自動執行兩者(這裏沒有選項)。對於成員方法,那麼子類必須專門引用超類的方法。 – Jaxidian 2010-04-29 18:58:11

1

在構造C#(和大多數語言)是不能繼承的,不能被重寫。但是,如果構造函數未顯式調用基構造函數,則會對基類的默認構造函數進行隱式調用。

+1

這是語言特定的 - 但(在C#中)還要求基類包含一個默認構造函數。如果沒有參數的構造函數,你會得到一個編譯器錯誤。 – 2010-04-29 19:04:20

1

只是爲了確認並非所有的語言都是一樣的:在Python中,默認行爲是替代超類構造函數。

class Car(): 
    def __init__(self, speed): 
    print "speed", speed 
    self.speed = speed 
class FordCar(Car): 
    def __init__(self, model): 
    print "model", model 
    self.speed = 180 
    self.model = model 

>>> FordCar("Mustang") 
model Mustang 

這是,imvho,明智的,因爲Python允許多重繼承。

相關問題