2010-04-29 40 views
5

Mã trong hàm tạo có thêm vào mã trong các hàm tạo lớp con không? Hoặc constructor của lớp con ghi đè lên superclass? Với ví dụ này constructor lớp cha:Mã trong hàm tạo có thêm vào mã trong các hàm tạo lớp con không?

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

... và constructor lớp con này:

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

Khi một thể hiện của FordCar được tạo ra, sẽ theo dõi này "Car" và "Ford" ??

Chỉnh sửa: Đối số cũng sẽ thêm? Xem mã cập nhật ở trên.

Trả lời

6

Có. Trong hầu hết các ngôn ngữ, hàm tạo lớp cơ sở được thi hành, sau đó là hàm tạo lớp con. Điều này sẽ làm cho nó theo dõi: "CAR", sau đó "FORD".

Cả hai nhà xây dựng lớp nên luôn luôn thực thi nếu bạn xây dựng một thể hiện của lớp con. Tùy thuộc vào ngôn ngữ được đề cập, việc thực thi thực tế và sự lựa chọn của hàm tạo lớp cơ sở, bao gồm cả thứ tự, có thể khác nhau. (Điều này đặc biệt đúng trong ngôn ngữ mà cho phép đa kế thừa - như thứ tự thực hiện có thể khó khăn để xác định ở cái nhìn đầu tiên trong một số trường hợp.)


Edit:

Trong hầu hết các ngôn ngữ, thay đổi nội dung của bạn mã sẽ không biên dịch. Phân lớp thường cần phải vượt qua các đối số cùng loại cho các hàm tạo lớp cơ sở. Đây là ngôn ngữ cụ thể, nhưng thường trông giống như sau:

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

Trong một số ngôn ngữ (chủ yếu là các ngôn ngữ động), ngôn ngữ sẽ cố gắng để tự động chuyển đổi, nhưng bạn thường có thể vẫn cần phải xác định đó của các nhà thầu phụ huynh để gọi .

Thông thường, bạn có thể làm:

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

Tôi sẽ luôn chạy? Ý nghĩa? –

+0

@Jeremy: Tôi đã viết lại - tốt hơn? –

+0

Yea! Và các đối số cũng sẽ tăng lên? Vui lòng xem mã cập nhật của tôi ở trên. –

4

Có, nó sẽ theo dõi cả hai. Thông thường các nhà xây dựng lớp con của bạn sẽ phải gọi hàm tạo của lớp cơ sở của bạn. Nếu có nhiều hơn một hàm tạo lớp cơ sở, thì bạn có thể có các tùy chọn. Tuy nhiên, nếu chỉ có một được đưa ra, thì bạn PHẢI đáp ứng các yêu cầu của nó.

Xét đoạn mã sau và đặc biệt chú ý đến các nhà thầu khác nhau và cách họ làm việc với nhà thầu của lớp cha:

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!!!!!!!!"; 
    } 
} 

[sửa]

Mã của bạn mà bạn thêm vào sẽ thường không biên dịch. Hàm tạo của lớp con thường PHẢI cung cấp tất cả các tham số cho hàm tạo của lớp cha. Không cung cấp cho họ không phải là một lựa chọn. Xem mã của tôi để xem cách các nhà xây dựng lớp con của tôi cung cấp các tham số cho các nhà xây dựng siêu lớp. Đôi khi, họ chỉ chuyển các thông số và các thời điểm khác mà họ thực sự đặt các giá trị mã hóa true/false mã hóa cứng vào.

+0

Không, khi một thể hiện của lớp con được tạo ra, nó cũng sẽ thực thi mã trong siêu lớp? –

+1

Đối với các nhà xây dựng, có, nó sẽ tự động thực hiện cả hai (bạn không có một tùy chọn ở đây). Đối với các phương thức thành viên, thì lớp con phải tham chiếu cụ thể phương thức của lớp cha. – Jaxidian

1

Constructors trong C# (và hầu hết các ngôn ngữ) không được thừa kế và không thể được ghi đè.Tuy nhiên, nếu hàm tạo không gọi một hàm tạo cơ sở một cách rõ ràng thì một cuộc gọi ngầm định được thực hiện tới hàm tạo mặc định của lớp cơ sở.

+1

Đây là ngôn ngữ cụ thể - nhưng (trong C#) cũng yêu cầu lớp cơ sở chứa hàm tạo mặc định. Nếu không có hàm tạo nào không có tham số, bạn sẽ gặp lỗi trình biên dịch. –

1

Chỉ để xác nhận không phải tất cả ngôn ngữ đều giống nhau: trong Python, hành vi mặc định là thay thế hàm tạo siêu lớp.

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 

Đây là, imvho, hợp lý vì Python cho phép đa kế thừa.

Các vấn đề liên quan