Khi chúng ta tạo một lớp kế thừa từ một lớp trừu tượng và khi chúng ta triển khai lớp trừu tượng được kế thừa tại sao chúng ta phải sử dụng từ khóa ghi đè?
"Tại sao?" những câu hỏi như thế này có thể khó trả lời vì chúng mơ hồ. Tôi sẽ giả định rằng câu hỏi của bạn là "những lập luận nào có thể được đưa ra trong quá trình thiết kế ngôn ngữ để tranh luận cho vị trí mà overridetừ khóa được yêu cầu ?"
Hãy bắt đầu bằng cách lùi lại một bước. Trong một số ngôn ngữ, giả sử, Java, các phương thức là ảo theo mặc định và được ghi đè tự động. Các nhà thiết kế của C # đã nhận thức được điều này và coi đó là một lỗ hổng nhỏ trong Java. C # không phải là "Java với những phần ngu ngốc bị loại bỏ" như một số người đã nói, nhưng các nhà thiết kế của C # rất muốn học hỏi từ các điểm thiết kế có vấn đề của C, C ++ và Java và không sao chép chúng trong C #.
Các nhà thiết kế C # coi việc ghi đè là một nguồn có thể có lỗi; xét cho cùng, đó là một cách để thay đổi hành vi của mã đã được thử nghiệm hiện có và điều đó thật nguy hiểm. Ghi đè không phải là điều nên được thực hiện ngẫu nhiên hoặc tình cờ; nó phải được thiết kế bởi một người nào đó suy nghĩ rất nhiều về nó . Đó là lý do tại sao các phương thức không ảo theo mặc định và tại sao bạn bắt buộc phải nói rằng bạn đang ghi đè một phương thức.
Đó là lý do cơ bản. Bây giờ chúng ta có thể đi vào một số lý luận nâng cao hơn.
Câu trả lời của StriplingWar Warrior đưa ra một cắt giảm tốt trong việc đưa ra một lập luận nâng cao hơn. Tác giả của lớp dẫn xuất có thể không hiểu rõ về lớp cơ sở, có thể có ý định tạo một phương thức mới và chúng ta không nên cho phép người dùng ghi đè do nhầm lẫn .
Mặc dù điểm này là hợp lý, có một số phản biện, chẳng hạn như:
- Tác giả của một lớp dẫn xuất có trách nhiệm biết mọi thứ về lớp cơ sở! Họ đang sử dụng lại mã đó và họ cần phải thực hiện kỹ lưỡng để hiểu kỹ mã đó trước khi sử dụng lại mã đó.
- Trong kịch bản cụ thể của bạn, phương thức ảo là trừu tượng; Sẽ là một lỗi nếu không ghi đè lên nó, và do đó không chắc là tác giả sẽ tạo ra một triển khai một cách tình cờ.
Sau đó, hãy đưa ra một lập luận thậm chí nâng cao hơn về điểm này. Trong hoàn cảnh nào, tác giả của một lớp dẫn xuất có thể được miễn vì không biết lớp cơ sở làm gì? Vâng, hãy xem xét kịch bản này:
- Tác giả lớp cơ sở tạo ra một lớp cơ sở trừu tượng B.
- Tác giả lớp dẫn xuất, trên một nhóm khác, tạo lớp D dẫn xuất với phương thức M.
- Tác giả lớp cơ sở nhận ra rằng các nhóm mở rộng lớp cơ sở B sẽ luôn cần cung cấp một phương thức M, vì vậy tác giả của lớp cơ sở thêm phương thức trừu tượng M.
- Khi lớp D được biên dịch lại, điều gì xảy ra?
Điều chúng tôi muốn xảy ra là tác giả của D được thông báo rằng một cái gì đó có liên quan đã thay đổi . Điều liên quan đã thay đổi là M bây giờ là một yêu cầu và việc thực hiện chúng phải bị quá tải. DM có thể cần thay đổi hành vi của nó một khi chúng ta biết rằng nó có thể được gọi từ lớp cơ sở. Điều đúng đắn cần làm là không âm thầm nói "oh, DM tồn tại và mở rộng BM". Điều chính xác để trình biên dịch thực hiện là thất bại và nói "hey, tác giả của D, hãy xem giả định này của bạn không còn hợp lệ và sửa mã của bạn nếu cần".
Trong ví dụ của bạn, giả sử overridelà tùy chọn trên SayHellovì nó đang ghi đè một phương thức trừu tượng. Có hai khả năng: (1) tác giả của mã dự định ghi đè một phương thức trừu tượng hoặc (2) phương thức ghi đè bị ghi đè do vô tình vì người khác đã thay đổi lớp cơ sở và mã hiện bị sai theo một cách tinh tế. Chúng tôi không thể phân biệt các khả năng này nếu overridelà tùy chọn .
Nhưng nếu overrideđược yêu cầu thì chúng ta có thể phân biệt ba kịch bản. Nếu có là một sai lầm có thể trong các mã sau đó overridelà mất tích . Nếu nó cố ý ghi đè thì overridecó mặt . Và nếu nó cố ý không ghi đè thì newcó mặt . Thiết kế của C # cho phép chúng tôi tạo ra những khác biệt tinh tế.
Ghi nhớ báo cáo trình biên dịch yêu cầu đọc suy nghĩ của nhà phát triển ; trình biên dịch phải suy ra từ mã sai mã chính xác mà tác giả có thể có trong tâm trí và đưa ra một lỗi chỉ ra chúng theo đúng hướng. Càng có nhiều manh mối, chúng tôi có thể khiến nhà phát triển để lại mã về những gì họ đã nghĩ, trình biên dịch có thể làm tốt hơn trong báo cáo lỗi và do đó bạn có thể tìm và sửa lỗi nhanh hơn.
Nhưng nói chung, C # được thiết kế cho một thế giới trong đó mã thay đổi . Thực tế, có rất nhiều tính năng của C # xuất hiện "kỳ quặc" vì chúng thông báo cho nhà phát triển khi một giả định được sử dụng là hợp lệ đã trở thành không hợp lệ vì một lớp cơ sở đã thay đổi. Lớp lỗi này được gọi là "lỗi lớp cơ sở dễ vỡ" và C # có một số giảm thiểu thú vị cho lớp lỗi này.