Có phải từ khóa 'ghi đè' chỉ là kiểm tra cho một phương thức ảo bị ghi đè?


226

Theo tôi hiểu, việc giới thiệu overridetừ khóa trong C ++ 11 không gì khác hơn là kiểm tra để đảm bảo rằng hàm được triển khai là overrideing của một virtualhàm trong lớp cơ sở.

Là nó?


50
Có.⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣
R. Martinho Fernandes

13
Đây không phải là một kiểm tra kép. Đó là kiểm tra duy nhất.
Nikos C.

13
này, ghi đè KHÔNG phải là một từ khóa, nó là một loại đường ngữ pháp. ghi đè int = 42; // OK
KAlO2

2
Nó cũng cải thiện khả năng đọc giải thích chức năng khai báo bị ghi đè;)
mots_g

5
Vì vậy, uh ... Khi nào C ++ 11 sẽ trở thành tiêu chuẩn đủ để họ bắt đầu dạy những thứ như thế này tại địa phương 4 năm của tôi? Khi nào họ sẽ biết?!
Cinch

Câu trả lời:


263

Đó thực sự là ý tưởng. Vấn đề là bạn rõ ràng về ý của bạn, do đó có thể chẩn đoán lỗi im lặng:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

Các mã trên biên dịch, nhưng không phải là những gì bạn có thể có nghĩa (lưu ý thiếu const). Nếu bạn nói thay vào đó, virtual int foo() overridethì bạn sẽ gặp lỗi trình biên dịch rằng trên thực tế chức năng của bạn không ghi đè bất cứ điều gì.


74
+1: Mặc dù, thật không may, đó là một chút cá trích đỏ khi mọi người đề xuất rằng overridetính năng mới "khắc phục" điều này; bạn phải nhớ sử dụng nó, giống như bạn nên nhớ để viết const;)
Các cuộc đua Lightness trong quỹ đạo

Tôi mới nhận ra explicitcác định nghĩa lớp không biến nó thành C ++ 11. Huh.
aschepler

1
@aschepler Và một explicitđịnh nghĩa lớp sẽ làm gì? Chưa bao giờ nghe về điều đó cả.
Christian Rau

18
@LightnessRacesinOrbit: Vâng, đó không phải là bằng chứng ngu ngốc; tuy nhiên, việc nhớ một quy tắc chung (viết điên cuồng overridekhi có ý định thực hiện) có nhiều khả năng hơn là ghi nhớ các trường hợp góc, nghĩa là không có tính tổng quát trong việc sao chép các chức năng của các nguyên mẫu khác nhau, chỉ có sự bất thường như thiếu consthoặc viếtchar thay vì intvv
legends2k

1
@Light, trường hợp sử dụng tốt nhất của overridespecifier được đề cập trong câu trả lời này , đó là tương lai hơn là ngay lập tức. Câu trả lời cho thấy rằng, giữ overridevới virtualphương pháp. Trong tương lai khi một người thay đổi nhầm chữ ký, tính hữu dụng của nó sẽ xuất hiện.
iammilind

35

Trích dẫn Wikipedia:

Mã định danh đặc biệt ghi đè có nghĩa là trình biên dịch sẽ kiểm tra (các) lớp cơ sở để xem liệu có một hàm ảo có chữ ký chính xác này không. Và nếu không có, trình biên dịch sẽ báo lỗi.

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

Chỉnh sửa (cố gắng cải thiện một chút câu trả lời):

Khai báo một phương thức là "ghi đè" có nghĩa là phương thức đó được dự định viết lại một phương thức (ảo) trên lớp cơ sở. Phương thức ghi đè phải có cùng chữ ký (ít nhất là đối với các tham số đầu vào) như phương thức mà nó dự định viết lại.

Tại sao điều này là cần thiết? Vâng, hai trường hợp lỗi phổ biến sau đây được ngăn chặn:

  1. một loại sai trong một phương thức mới. Trình biên dịch, không biết rằng nó đang có ý định viết một phương thức trước đó, chỉ cần thêm nó vào lớp như một phương thức mới. Vấn đề là phương thức cũ vẫn còn đó, phương thức mới được thêm vào chỉ là quá tải. Trong trường hợp này, tất cả các cuộc gọi hướng tới phương thức cũ sẽ hoạt động như trước đây, mà không có bất kỳ thay đổi nào trong hành vi (đó sẽ là mục đích chính của việc viết lại).

  2. người ta quên khai báo phương thức trong siêu lớp là "ảo", nhưng vẫn cố gắng viết lại nó trong một lớp con. Mặc dù điều này rõ ràng sẽ được chấp nhận, nhưng hành vi sẽ không chính xác như dự định: phương thức này không phải là ảo, vì vậy việc truy cập thông qua con trỏ tới siêu lớp sẽ kết thúc bằng cách gọi phương thức (siêu lớp ') cũ thay vì phương thức (lớp con') mới.

Thêm "ghi đè" rõ ràng làm rõ điều này: thông qua điều này, người ta đang nói với trình biên dịch rằng có ba điều đang mong đợi:

  1. có một phương thức có cùng tên trong siêu lớp
  2. phương thức này trong siêu lớp được khai báo là "ảo" (có nghĩa là, dự định viết lại)
  3. phương thức trong siêu lớp có chữ ký (đầu vào *) giống như phương thức trong lớp con (phương thức viết lại)

Nếu bất kỳ trong số này là sai, thì một lỗi được báo hiệu.

* lưu ý: tham số đầu ra đôi khi khác nhau, nhưng loại liên quan. Đọc về biến đổi covariant và contravariant nếu quan tâm.


31

Tìm thấy " ghi đè " là hữu ích khi ai đó cập nhật chữ ký phương thức ảo lớp cơ sở, chẳng hạn như thêm một tham số tùy chọn nhưng quên cập nhật chữ ký phương thức lớp dẫn xuất. Trong trường hợp đó, các phương thức giữa lớp cơ sở và lớp dẫn xuất không còn quan hệ đa hình nữa. Nếu không có khai báo ghi đè, thật khó để tìm ra loại lỗi này.


1
+1. Mặc dù overridelà một cách tuyệt vời để khám phá những vấn đề như vậy, nhưng phạm vi kiểm tra đơn vị tốt cũng sẽ giúp ích.
vỡ mộng

1
Đó chính xác là lý do tại sao tôi rất vui mừng về nhà đầu cơ mới đó. Vấn đề duy nhất là tính năng này phải được áp dụng để ngăn ngừa lỗi do thay đổi trong các lớp cơ sở. ;-)
Sói


2

Dự thảo tiêu chuẩn C ++ 17

Sau khi xem qua tất cả các overridelần truy cập vào bản nháp tiêu chuẩn C ++ 17 N4659 , tài liệu tham khảo duy nhất tôi có thể tìm thấy cho overrideđịnh danh là:

5 Nếu một chức năng ảo được đánh dấu bằng ghi đè virt-specifier và không ghi đè chức năng thành viên của lớp cơ sở, chương trình sẽ không được định dạng. [ Thí dụ:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

- ví dụ kết thúc]

Vì vậy, tôi nghĩ rằng có thể thổi tung các chương trình sai thực sự là hiệu ứng duy nhất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.