2010-01-08 64 views
9

Cách tốt nhất để khởi tạo các hằng số hoặc các trường khác trong các lớp kế thừa là gì? Tôi nhận ra có nhiều lỗi cú pháp trong ví dụ này, nhưng đây là ví dụ tốt nhất để giải thích rõ ràng những gì tôi đang cố gắng làm.Khởi tạo các trường trong các lớp kế thừa

public abstract class Animal { 
    public abstract const string Name; // #1 
    public abstract const bool CanFly; 
    public abstract double Price; // price is not const, because it can be modified 

    public void Fly() { 
    if (!CanFly) 
     Debug.Writeln("{0}s can't fly.", Name); 
    else 
     Debug.Writeln("The {0} flew.", Name); 
    } 
} 

public class Dog : Animal { 
    public override const string Name = "Dog"; // #2 
    public override const bool CanFly = false; 
    public override double Price = 320.0; 
} 

public class Bird : Animal { 
    public override const string Name = "Bird"; 
    public override const bool CanFly = true; 
    public override double Price = 43.0; 
} 

Một vài điều tôi đang cố gắng để hoàn thành:

  • lớp cơ sở phải gán những 3 lĩnh vực.
  • Lý tưởng nhất là tôi muốn các trường được khởi tạo này ở cùng nhau ở đầu lớp để tôi có thể xem các hằng số nào được gán cho mỗi lớp và thay đổi chúng bất cứ khi nào cần.
  • Các trường Tên và CanFly không thể thay đổi.

Tôi biết rằng bạn có thể khởi tạo các trường này trong một hàm tạo (nếu bạn loại bỏ const), nhưng sau đó chúng không được đảm bảo được chỉ định. Nếu bạn có các trường này dưới dạng thuộc tính thay thế và ghi đè chúng, bạn vẫn cần phải khởi tạo trường sao lưu của thuộc tính. Làm thế nào bạn sẽ thực hiện điều này?

Một vài lỗi cú pháp nó than phiền về:

  • Các modifier 'trừu tượng' không hợp lệ trên các lĩnh vực. Thay vào đó, hãy thử sử dụng thuộc tính. (# 1)
  • Một lĩnh vực const đòi hỏi một giá trị được cung cấp (# 1)
  • Các modifier 'đè' không hợp lệ cho mặt hàng này (# 2)
+3

Tôi nghĩ bạn hiểu nhầm những hằng số là gì. Hằng số là giá trị không bao giờ thay đổi trong suốt lịch sử vũ trụ; do đó, tên "hằng số". Ví dụ tốt về hằng số: số trứng trong một tá, số nguyên tử chì. Xấu: số phiên bản của ứng dụng của bạn; điều này thay đổi theo thời gian. Khủng khiếp: giá của một thùng dầu; thay đổi sau vài giây. Nếu có một trường có giá trị có thể thay đổi trong suốt thời gian tồn tại của ứng dụng, nó không phải là hằng số. –

+0

Cảm ơn lời giải thích. Tôi đoán tôi là một chút bối rối bởi vì các lĩnh vực Dog.Name và Dog.CanFly không bao giờ nên được thay đổi, do đó tôi sẽ nghĩ rằng họ nên được hằng số. Tuy nhiên, các trường Animal.Name và Animal.CanFly sẽ được thay đổi bởi các lớp kế thừa, vì vậy chúng không phải là hằng số. Tôi đã cố gắng để xác định chúng như là hằng số trong các lớp thừa hưởng chỉ, mà tôi đoán bạn không thể làm. – Senseful

+0

Để lập mô hình một giá trị được đặt một lần vào thời gian xây dựng và không bao giờ thay đổi sau đó, hãy sử dụng trường chỉ đọc. Các trường chỉ đọc có thể là các trường thể hiện, trong trường hợp này bạn có thể có một giá trị khác nhau cho từng cá thể hoặc tĩnh, trong trường hợp đó, mỗi cá thể đều có cùng giá trị. –

Trả lời

19

Nếu một lớp cơ sở đòi hỏi một giá trị được cung cấp bởi một lớp được thừa kế, hai cách phổ biến nhất là:

Yêu cầu nó trong constructor:

public readonly double Price; 

protected BaseClass(double price) 
{ 
    this.Price = price; 
} 

nguồn gốc lớp phải vượt qua giá vào constructor:

public Derived() : base(32) 
{ 
} 

Hoặc, hãy nó trở thành một tài sản trừu tượng:

public abstract double Price { get; } 

lớp Derived phải cung cấp một số cách để trả về giá trị (mặc dù nơi họ có được nó lên đến lớp được thừa kế, mà trong nhiều trường hợp cung cấp linh hoạt hơn):

public override double Price 
{ 
    get 
    { 
     return 32; 
    } 
} 
+1

Những bất lợi tiềm năng của một thuộc tính trừu tượng là các lớp dẫn xuất có thể phá vỡ bảo đảm "không bao giờ thay đổi trong suốt cuộc đời", có thể được thực thi với trường chỉ đọc + ctor. –

5

Nếu bạn muốn có đặc biệt các trường trong lớp trừu tượng của bạn, nhưng không muốn định nghĩa chúng trong lớp cơ sở, bạn có thể yêu cầu những người triển khai cung cấp các giá trị thông qua hàm tạo.

public abstract class MyClass 
{ 
    private readonly double price; 

    protected MyClass(double price) 
    { 
     this.price = price 
    } 
} 

Với một lớp cơ sở như vậy, tất cả các lớp thừa kế phải cung cấp một giá trị cho các lớp cơ sở constructor, hoặc mã sẽ không biên dịch. Dưới đây là một ví dụ về làm thế nào mà có thể trông:

public class Foo : MyClass 
{ 
    public Foo() : base(42) { } 
} 
1

Bạn có thể sử dụng readonly và một constructor internal để thực thi hành vi này nhưng nó sẽ hơi thiếu.Nếu bạn đi với điều này những người thừa kế sẽ cần phải được trong cùng một không gian tên/lắp ráp để tận dụng lợi thế của các nhà xây dựng nội bộ.

0

mô hình khác là tạo accessor (thuộc tính) ảo. Điều này buộc các lớp dẫn xuất để thực hiện nó.

Ưu điểm của điều này là 'canfly' có thể có câu trả lời phụ thuộc vào thời gian (nói) trong ngày.

1

Các lỗi bạn nhận được ngày càng ít nói cho bạn biết phải làm gì. Bạn muốn sử dụng các thuộc tính trừu tượng, không phải các trường, cho NameCanFly, trong khi Price sẽ là một thuộc tính bình thường. Trong các lớp dẫn xuất, các thuộc tính trừu tượng sẽ là chỉ đọc và trả về một hằng số, trong mỗi trường hợp. Trong mã:

public abstract class Animal { 
    public abstract string Name { get; } 
    public abstract bool CanFly { get; } 
    public double Price { get; set; } 
    // etc 
} 

public class Dog : Animal { 
    public override string Name { get { return "Dog"; } } 
    public override bool CanFly { get { return false; } } 
    public Dog() { Price = 320.0; } 
} 

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