Добавляет ли код в конструкторе код в конструкторах подкласса? - PullRequest
5 голосов
/ 29 апреля 2010

Добавляет ли код в конструкторе код в конструкторах подкласса? Или конструктор подкласса переопределяет суперкласс? Учитывая этот пример конструктора суперкласса:

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

... и этот конструктор подкласса:

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

Когда будет создан экземпляр FordCar, будет ли эта трассировка "Car" и "Ford" ??

Редактировать: Будут ли аргументы добавлены? Смотрите обновленный код выше.

Ответы [ 4 ]

6 голосов
/ 29 апреля 2010

Да. В большинстве языков выполняется конструктор базового класса, а затем конструктор подклассов. Это заставит его отследить: «АВТОМОБИЛЬ», затем «ФОРД».

Оба конструктора класса должны всегда выполняться, если вы создаете экземпляр подкласса. В зависимости от рассматриваемого языка фактическое выполнение и выбор конструктора базового класса, включая упорядочение, могут различаться. (Это особенно верно для языков, которые допускают множественное наследование - поскольку порядок выполнения может быть трудно определить на первый взгляд в некоторых случаях.)


Edit:

На большинстве языков ваш отредактированный код не будет компилироваться. Подкласс обычно должен передавать аргументы того же типа конструкторам базового класса. Это зависит от языка, но часто выглядит примерно так:

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

В некоторых языках (в основном, в динамических языках) язык будет пытаться автоматически преобразовывать, но вам все еще может потребоваться указать, какой из родительских конструкторов вызывать.

Часто вы можете сделать:

function FordCar(int: speed, model: string) : Car(speed) {
    trace("FORD model " + model)
}
4 голосов
/ 29 апреля 2010

Да, это будет отслеживать оба. Обычно конструкторы вашего дочернего класса должны вызывать конструктор вашего базового класса. Если задано более одного конструктора базового класса, у вас могут быть опции. Однако, если указан только один, вы ДОЛЖНЫ удовлетворить его требования.

Рассмотрим следующий код и обратите особое внимание на различные конструкторы и то, как они работают с конструкторами суперкласса:

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.

1 голос
/ 29 апреля 2010

Просто чтобы подтвердить, что не все языки одинаковы: в 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

Это очень разумно, потому что Python допускает множественное наследование.

1 голос
/ 29 апреля 2010

Конструкторы в C # (и большинстве языков) не наследуются и не могут быть переопределены. Однако, если конструктор не вызывает явно базовый конструктор, делается неявный вызов конструктору по умолчанию базового класса.

...