Tại sao một hàm ảo thuần túy được khởi tạo bằng 0?


147

Chúng tôi luôn khai báo một hàm ảo thuần túy là:

virtual void fun () = 0 ;

Tức là, nó luôn được gán cho 0.

Điều tôi hiểu là điều này là để khởi tạo mục nhập vtable cho hàm này thành NULL và bất kỳ giá trị nào khác ở đây đều dẫn đến lỗi thời gian biên dịch. Cách hiểu này có đúng hay không?


12
Lưu ý rằng vtable không phải là một yêu cầu ngôn ngữ, mà chỉ là một tùy chọn triển khai cho các phương thức ảo. Một trình biên dịch có thể tạo ra sự trừu tượng tương tự với cách triển khai khác (nghĩa là không có vtable và không có phần tử nào có 0)
David Rodríguez - dribeas

@hype Re câu hỏi bổ sung của bạn - đó là những gì câu trả lời của tôi (và một số người khác) nói.

Chỉ tò mò, chuyện gì sẽ xảy ra nếu tôi cho, virtual void func() = 100;
krithikaGopalakrisnan 30/07/19

Câu trả lời:


161

Lý do =0được sử dụng là Bjarne Stroustrup không nghĩ rằng anh ta có thể có được một từ khóa khác, chẳng hạn như "thuần túy" trong cộng đồng C ++ tại thời điểm tính năng này được triển khai. Điều này được mô tả trong cuốn sách của ông, The Design & Evolution of C ++ , phần 13.2.3:

Cú pháp tò mò = 0 đã được chọn ... bởi vì tại thời điểm đó tôi thấy không có cơ hội nhận được từ khóa mới.

Ông cũng tuyên bố rõ ràng rằng điều này không cần đặt mục nhập vtable thành NULL và làm như vậy không phải là cách tốt nhất để thực hiện các chức năng ảo thuần túy.


4
Đúng, đó chỉ là cú pháp. Tôi đã thấy rất nhiều dự án #define PURE = 0 và họ sẽ nói khoảng trống ảo Foo () PURE;
i_am_jorf

79
Hãy Thiên Chúa giữ tôi ra khỏi những dự án :-)

27
Nó kém hơn rất nhiều so với #define BEGIN {#define END} ;-) và đôi khi tôi đã thấy điều đó.
Toon Krijthe

5
Kiểu điều tiện lợi này khiến tôi nghĩ rằng C ++ không được đánh bóng cho lắm. Thật kỳ lạ khi xem xét nó được sử dụng rất nhiều. Tôi hy vọng ngôn ngữ sẽ tốt hơn với những ngày trôi qua.
jokoon

19
Vì vậy, nói cách khác, Bjarne đã "phải đối mặt với một thời hạn" và "sử dụng một hack" để vượt qua một "lỗ hổng thiết kế";) (Chỉ cần là khôi hài)
Carl

78

Như với hầu hết các câu hỏi "Tại sao" về thiết kế của C ++, nơi đầu tiên để tìm là Thiết kế và Tiến hóa của C ++ , bởi Bjarne Stroustrup 1 :

=0Cú pháp tò mò đã được chọn qua phương án thay thế rõ ràng là giới thiệu một từ khóa mới purehoặc abstractbởi vì tại thời điểm đó tôi thấy không có cơ hội nhận được một từ khóa mới được chấp nhận. Nếu tôi đề xuất pure, Phiên bản 2.0 sẽ được phát hành mà không có các lớp trừu tượng. Đưa ra lựa chọn giữa một cú pháp đẹp hơn và các lớp trừu tượng, tôi đã chọn các lớp trừu tượng. Thay vì mạo hiểm trì hoãn và phát sinh một số trận đánh nhất định pure, tôi đã sử dụng quy ước C và C ++ truyền thống về việc sử dụng 0 để thể hiện "không có ở đó". Các =0phù hợp cú pháp với quan điểm của tôi rằng một cơ quan chức năng là khởi tạo cho một chức năng cũng với quan điểm (đơn giản, nhưng thường đầy đủ) của tập hợp các hàm ảo được thực hiện như một vector của các con trỏ hàm. [...]

1 §13.2.3 Cú pháp


29

Mục 9.2 của tiêu chuẩn C ++ đưa ra cú pháp cho các thành viên lớp. Nó bao gồm sản xuất này:

pure-specifier:
    = 0

Không có gì đặc biệt về giá trị. "= 0" chỉ là cú pháp để nói "hàm này là thuần ảo". Nó không có gì để làm với khởi tạo hoặc con trỏ null hoặc giá trị số 0, mặc dù sự tương tự với những thứ đó có thể có giá trị ghi nhớ.


5
+1 để tham khảo Tiêu chuẩn C ++. Thật đáng ngạc nhiên khi một trong những câu trả lời tốt nhất có thể và chỉ có 1 phiếu bầu cho đến nay. Đọc tiêu chuẩn nên là bước đầu tiên để giải các câu hỏi về C ++.
mloskot

7
@mloskot: có thể vì nó không trả lời câu hỏi của OP, chỉ cần khôi phục lại tình huống?
chỉ là ai đó

6
@just someone - Nó bao gồm trích dẫn tiêu chuẩn trong đó nêu rõ cú pháp của khai báo hàm ảo thuần túy và cú pháp sử dụng trình xác định thuần túy = 0Bạn còn muốn biết gì nữa không? Nó sẽ giống như hỏi tại sao thân hàm được gói bằng {} Câu trả lời sẽ là, bởi vì đó là những gì cú pháp C ++ định nghĩa.
mloskot

19

Tôi không chắc có ý nghĩa gì đằng sau điều này. Nó chỉ là cú pháp của ngôn ngữ.


16

C ++ luôn tránh xa việc giới thiệu các từ khóa mới, vì các từ dành riêng mới phá vỡ các chương trình cũ sử dụng các từ này để nhận dạng. Nó thường được xem là một trong những thế mạnh của ngôn ngữ mà nó tôn trọng mã cũ càng nhiều càng tốt.

Các = 0cú pháp có thể thực sự đã được chọn vì nó tương tự như thiết lập một mục vtable đến 0, nhưng điều này là hoàn toàn mang tính biểu tượng. .


3
+1 để giải thích nhược điểm của việc giới thiệu từ khóa mới. Điều đó hữu ích để hiểu cơ sở lý luận, nhưng cú pháp C ++ có vẻ vô lý đối với tôi và tôi ước họ sẽ làm cho nó dễ đọc hơn với con người - một puretừ khóa sẽ rất tuyệt trong cuốn sách của tôi. Dù sao, thật tốt để hiểu lý do.
Keith Pinson

@KeithPinson Nếu bạn muốn một từ khóa thuần túy, bạn có thể #define pure = 0.
jdh8

@ jdh8: Ừ. Chỉ là ... Ừ.
sbi

Một ghi chú bên lề, trong một lớp học với Bjarne, anh cho biết anh thực sự muốn đưa từ khóa "thuần túy" vào C ++ ... nhưng anh đã cố gắng đưa nó vào rất muộn trong chu kỳ trước khi trình biên dịch C ++ sẽ được chuyển đi (IIRC ít hơn hai tuần). Rõ ràng, nó đã không xuất hiện.
ThePhD

@ThePhD: ISTR anh ấy cũng nói điều này ở đâu đó trong D & E. (Tuy nhiên, tôi quá lười để tìm kiếm nó.)
sbi

11

C ++ phải có cách phân biệt hàm ảo thuần với khai báo hàm ảo bình thường. Họ đã chọn sử dụng = 0cú pháp. Họ có thể dễ dàng làm điều tương tự bằng cách thêm một từ khóa thuần túy. Nhưng C ++ khá miễn cưỡng khi thêm các từ khóa mới và thích sử dụng các cơ chế khác để giới thiệu các tính năng.


2
-0: khi bạn không có gì đáng kể để tự mình nói, hãy sử dụng một trích dẫn mở rộng (xem câu trả lời của Jerry Coffin cho +1;)
chỉ cần ai đó

7

Không có gì là "khởi tạo" hoặc "được chỉ định" trong trường hợp này. = 0chỉ trong một cấu trúc cú pháp bao gồm =0mã thông báo, hoàn toàn không liên quan đến khởi tạo hoặc gán.

Nó không liên quan đến bất kỳ giá trị thực tế nào trong "vtable". Ngôn ngữ C ++ không có khái niệm "vtable" hay anythng như thế. "Vtables" khác nhau không gì khác hơn là chi tiết về việc triển khai cụ thể.


3

Tôi nhớ rằng đọc lời biện minh cho cú pháp hài hước là nó dễ dàng hơn (về mặt chấp nhận tiêu chuẩn) so với việc giới thiệu một từ khóa khác sẽ làm điều tương tự.

Tôi tin rằng điều này đã được đề cập trong The Design and Evolution of C ++ của Bjarne Stroustrup.


2

Tôi cho rằng đây chỉ là một phần của ngữ pháp C ++. Tôi không nghĩ có bất kỳ hạn chế nào đối với cách trình biên dịch thực sự thực hiện điều này cho một định dạng nhị phân cụ thể. Giả định của bạn có lẽ phù hợp với trình biên dịch C ++ ngày đầu.


2

Việc = 0khai báo một hàm ảo thuần túy .

Điều dễ hiểu là điều này là để khởi tạo mục nhập vtable cho hàm này thành NULL và bất kỳ giá trị nào khác ở đây dẫn đến lỗi thời gian biên dịch

Tôi không nghĩ đó là sự thật. Đó chỉ là cú pháp đặc biệt. Các vtable được xác định thực hiện. Không ai nói rằng một mục nhập vtable cho một thành viên thuần túy phải thực sự bị xóa khi xây dựng (mặc dù hầu hết các trình biên dịch xử lý vtables tương tự).


4
Điều đó thực sự không đúng. Không có gì sai khi cung cấp một định nghĩa cho một hàm ảo thuần túy. Điều duy nhất = 0làm là làm cho toàn bộ lớp trừu tượng và cấm các cuộc gọi ảo đến các hàm thuần túy. Các cuộc gọi không ảo vẫn hoàn toàn ổn, đó là khi định nghĩa (nếu bạn cung cấp) được sử dụng.
AnT

Chỉ cần nhìn vào đầu ra godbolt. Không có chỗ cho sự mơ hồ hoặc đầu cơ. Tôi sẽ xem lại bản thân mình sau
Lewis Kelsey

Có vẻ như nó thay thế mục nhập bằng __cxa_pure_virtual arobenko.gitbooks.io/bare_metal_cpp/content/compilerDefput/ Kẻ thay vì Base :: f ()
Lewis Kelsey

1

Chà, bạn cũng có thể khởi tạo mục vtable để trỏ đến một chức năng thực tế "

 virtual void fun()
 {
     //dostuff()
 }

Có vẻ trực quan rằng mục vtable có thể được xác định để chỉ ra không (0) hoặc đến một hàm. Để bạn chỉ định giá trị của riêng bạn cho nó có thể sẽ dẫn đến việc nó trỏ đến rác thay vì một hàm. Nhưng đó là lý do tại sao "= 0" được cho phép và "= 1" thì không. Tôi nghi ngờ Neil Butterworth đúng về lý do tại sao "= 0" được sử dụng


1
Ngay cả tôi cũng có ý kiến ​​tương tự nhưng vì nhiều người đã trích dẫn các tiêu chuẩn và nhận xét của Bjarne như nhau, chúng tôi có cơ hội tranh luận tối thiểu :)
mukeshkumar
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.