2010-04-29 65 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允许多重继承。