Tại sao C ++ không có phản xạ?


337

Đây là một câu hỏi hơi kỳ quái. Mục tiêu của tôi là tìm hiểu quyết định thiết kế ngôn ngữ và xác định các khả năng phản ánh trong C ++.

  1. Tại sao ủy ban ngôn ngữ C ++ không hướng tới việc thực hiện phản xạ trong ngôn ngữ? Sự phản chiếu có quá khó trong một ngôn ngữ không chạy trên máy ảo (như java) không?

  2. Nếu một người thực hiện phản xạ cho C ++, những thách thức sẽ là gì?

Tôi đoán việc sử dụng sự phản chiếu là nổi tiếng: các biên tập viên có thể dễ dàng viết hơn, mã chương trình sẽ nhỏ hơn, các giả có thể được tạo cho các bài kiểm tra đơn vị, v.v. Nhưng sẽ thật tuyệt nếu bạn có thể nhận xét về việc sử dụng sự phản chiếu quá.

Câu trả lời:


631

Có một số vấn đề với sự phản chiếu trong C ++.

  • Đó là rất nhiều công việc để thêm và ủy ban C ++ khá bảo thủ và không dành thời gian cho các tính năng mới triệt để trừ khi họ chắc chắn rằng nó sẽ được đền đáp. . C ++ 0x. Động lực cho tính năng này là thoát khỏi #includehệ thống, nhưng nó cũng sẽ cho phép ít nhất một số siêu dữ liệu).

  • Bạn không trả tiền cho những gì bạn không sử dụng. Đó là một trong những triết lý thiết kế cơ bản bắt buộc phải có trong C ++. Tại sao mã của tôi phải mang theo siêu dữ liệu nếu tôi có thể không bao giờ cần nó? Hơn nữa, việc bổ sung siêu dữ liệu có thể ngăn cản trình biên dịch tối ưu hóa. Tại sao tôi phải trả chi phí đó trong mã của mình nếu tôi có thể không bao giờ cần siêu dữ liệu đó?

  • Điều này dẫn chúng ta đến một điểm quan trọng khác: C ++ thực hiện rất ít đảm bảo về mã được biên dịch. Trình biên dịch được phép thực hiện khá nhiều thứ nó thích, miễn là chức năng kết quả là những gì được mong đợi. Ví dụ, các lớp học của bạn không bắt buộc phải ở đó . Trình biên dịch có thể tối ưu hóa chúng đi, nội tuyến mọi thứ chúng làm và nó thường làm điều đó, bởi vì ngay cả mã mẫu đơn giản cũng có xu hướng tạo ra khá nhiều tức thời mẫu. Thư viện chuẩn C ++ dựa trên sự tối ưu hóa mạnh mẽ này. Functor chỉ hoạt động nếu chi phí khởi tạo và phá hủy đối tượng có thể được tối ưu hóa. operator[]trên một vectơ chỉ có thể so sánh với việc lập chỉ mục mảng thô trong hiệu năng vì toàn bộ toán tử có thể được nội tuyến và do đó loại bỏ hoàn toàn khỏi mã được biên dịch. C # và Java đảm bảo rất nhiều về đầu ra của trình biên dịch. Nếu tôi định nghĩa một lớp trong C #, thì lớp đó sẽ tồn tại trong tập hợp kết quả. Ngay cả khi tôi không bao giờ sử dụng nó. Ngay cả khi tất cả các cuộc gọi đến các chức năng thành viên của nó có thể được nội tuyến. Lớp học phải ở đó, để sự phản chiếu có thể tìm thấy nó. Một phần của điều này được giảm bớt bằng cách biên dịch C # thành mã byte, có nghĩa là trình biên dịch JIT có thểxóa định nghĩa lớp và hàm nội tuyến nếu nó thích, ngay cả khi trình biên dịch C # ban đầu không thể. Trong C ++, bạn chỉ có một trình biên dịch và nó phải xuất mã hiệu quả. Nếu bạn được phép kiểm tra siêu dữ liệu của một tệp thực thi C ++, bạn sẽ thấy mọi lớp được định nghĩa, điều đó có nghĩa là trình biên dịch sẽ phải bảo toàn tất cả các lớp được xác định, ngay cả khi chúng không cần thiết.

  • Và sau đó là các mẫu. Các mẫu trong C ++ không có gì giống như thuốc generic trong các ngôn ngữ khác. Mỗi khởi tạo mẫu tạo ra một loại mới . std::vector<int>là một lớp hoàn toàn riêng biệt từ std::vector<float>. Điều đó thêm vào rất nhiều loại khác nhau trong toàn bộ chương trình. Phản ánh của chúng ta nên nhìn thấy gì? Các mẫu std::vector ? Nhưng làm thế nào nó có thể, vì đó là một cấu trúc mã nguồn, không có ý nghĩa gì trong thời gian chạy? Nó phải xem các lớp riêng biệt std::vector<int>std::vector<float>. Và std::vector<int>::iteratorstd::vector<float>::iterator, tương tự choconst_iteratorvà như thế. Và một khi bạn bước vào siêu lập trình mẫu, bạn sẽ nhanh chóng kết thúc việc tạo ra hàng trăm mẫu, tất cả đều được trình biên dịch và loại bỏ một lần nữa bởi trình biên dịch. Chúng không có ý nghĩa gì, ngoại trừ là một phần của siêu dữ liệu thời gian biên dịch. Tất cả hàng trăm lớp học này có thể được nhìn thấy để phản ánh? Họ sẽ phải làm thế, bởi vì nếu không thì sự phản chiếu của chúng ta sẽ vô ích, nếu nó thậm chí không đảm bảo rằng các lớp tôi đã xác định sẽ thực sự ở đó . Và một vấn đề phụ là lớp mẫu không tồn tại cho đến khi nó được khởi tạo. Hãy tưởng tượng một chương trình sử dụng std::vector<int>. Hệ thống phản chiếu của chúng ta có thể nhìn thấy std::vector<int>::iterator? Một mặt, bạn chắc chắn mong đợi như vậy. Đây là một lớp học quan trọng, và nó xác định theo std::vector<int>, mà khôngtồn tại trong siêu dữ liệu. Mặt khác, nếu chương trình không bao giờ thực sự sử dụng mẫu lớp lặp này, kiểu của nó sẽ không bao giờ được khởi tạo, và vì vậy trình biên dịch sẽ không tạo lớp ở vị trí đầu tiên. Và đã quá muộn để tạo ra nó trong thời gian chạy, vì nó yêu cầu quyền truy cập vào mã nguồn.

  • Và cuối cùng, sự phản chiếu không hoàn toàn quan trọng trong C ++ như trong C #. Lý do là một lần nữa, siêu lập trình mẫu. Nó không thể giải quyết mọi thứ, nhưng trong nhiều trường hợp nếu bạn không dùng đến sự phản chiếu, có thể viết một siêu biểu đồ thực hiện điều tương tự vào thời gian biên dịch. boost::type_traitslà một ví dụ đơn giản. Bạn muốn biết về loại T? Kiểm tra nó type_traits. Trong C #, bạn sẽ phải câu cá xung quanh sau khi sử dụng loại phản chiếu. Sự phản chiếu vẫn sẽ hữu ích cho một số thứ (công dụng chính mà tôi có thể thấy, mà siêu lập trình không thể thay thế dễ dàng, là cho mã tuần tự hóa được tạo tự động), nhưng nó sẽ mang lại một số chi phí đáng kể cho C ++, và nó không cần thiết thường xuyên như vậy là trong các ngôn ngữ khác.

Chỉnh sửa: Đáp lại các bình luận:

cdleary: Có, các biểu tượng gỡ lỗi làm một cái gì đó tương tự, trong đó chúng lưu trữ siêu dữ liệu về các loại được sử dụng trong tệp thực thi. Nhưng họ cũng bị những vấn đề tôi mô tả. Nếu bạn đã từng thử gỡ lỗi bản dựng phát hành, bạn sẽ biết ý tôi là gì. Có những khoảng trống logic lớn nơi bạn đã tạo một lớp trong mã nguồn, đã được đưa vào trong mã cuối cùng. Nếu bạn sử dụng sự phản chiếu cho bất cứ điều gì hữu ích, bạn sẽ cần nó đáng tin cậy và nhất quán hơn. Như vậy, các kiểu sẽ biến mất và biến mất gần như mỗi khi bạn biên dịch. Bạn thay đổi một chi tiết nhỏ và trình biên dịch quyết định thay đổi loại nào được nội tuyến và loại nào không, như một phản hồi. Làm thế nào để bạn trích xuất bất cứ điều gì hữu ích từ đó, khi bạn ' thậm chí không đảm bảo rằng các loại có liên quan nhất sẽ được trình bày trong siêu dữ liệu của bạn? Loại bạn đang tìm kiếm có thể đã ở đó trong bản dựng trước, nhưng bây giờ nó đã biến mất. Và ngày mai, một người nào đó sẽ kiểm tra một thay đổi nhỏ vô tội thành một chức năng vô tội nhỏ, làm cho loại này đủ lớn để nó không bị đảo ngược hoàn toàn, vì vậy nó sẽ trở lại. Điều đó vẫn hữu ích cho các biểu tượng gỡ lỗi, nhưng không nhiều hơn thế. Tôi ghét cố gắng tạo mã tuần tự hóa cho một lớp theo các điều khoản đó. nhưng không nhiều hơn thế Tôi ghét cố gắng tạo mã tuần tự hóa cho một lớp theo các điều khoản đó. nhưng không nhiều hơn thế Tôi ghét cố gắng tạo mã tuần tự hóa cho một lớp theo các điều khoản đó.

Evan Teran: Tất nhiên những vấn đề này có thể được giải quyết. Nhưng điều đó rơi trở lại điểm số 1 của tôi. Nó sẽ tốn rất nhiều công sức và ủy ban C ++ có rất nhiều điều họ cảm thấy quan trọng hơn. Là lợi ích của việc có được một số phản ánh hạn chế (và nó sẽ bị hạn chế) trong C ++ có thực sự đủ lớn để biện minh cho việc tập trung vào đó với chi phí của các tính năng khác không? Có thực sự có một lợi ích to lớn trong việc thêm các tính năng mà ngôn ngữ cốt lõi (hầu hết) có thể được thực hiện thông qua các thư viện và bộ tiền xử lý như của QT không? Có lẽ, nhưng nhu cầu ít khẩn cấp hơn nhiều so với việc các thư viện như vậy không tồn tại. Đối với các đề xuất cụ thể của bạn, tôi tin rằng việc không cho phép nó trên các mẫu sẽ làm cho nó hoàn toàn vô dụng. Bạn sẽ không thể sử dụng sự phản chiếu trên thư viện tiêu chuẩn, ví dụ. Những loại phản xạ sẽ 'std::vector? Mẫu là một phần rất lớn của C ++. Một tính năng không hoạt động trên các mẫu về cơ bản là vô dụng.

Nhưng bạn đã đúng, một số hình thức phản ánh có thể được thực hiện. Nhưng nó sẽ là một thay đổi lớn trong ngôn ngữ. Như bây giờ, các kiểu chỉ là một cấu trúc thời gian biên dịch. Chúng tồn tại vì lợi ích của trình biên dịch, và không có gì khác. Một khi các mã đã được biên soạn, có không có các lớp học. Nếu bạn kéo dài bản thân, bạn có thể lập luận rằng các chức năng vẫn tồn tại, nhưng thực sự, tất cả chỉ có một loạt các hướng dẫn trình biên dịch nhảy và rất nhiều thao tác đẩy / pop stack. Không có nhiều thứ để tiếp tục, khi thêm siêu dữ liệu đó.

Nhưng như tôi đã nói, có một đề xuất thay đổi mô hình biên dịch, thêm các mô-đun độc lập, lưu trữ siêu dữ liệu cho các loại chọn, cho phép các mô-đun khác tham chiếu chúng mà không phải lộn xộn với #includes. Đó là một khởi đầu tốt, và thành thật mà nói, tôi ngạc nhiên khi ủy ban tiêu chuẩn không chỉ đưa ra đề xuất vì đó là một thay đổi quá lớn. Vậy có lẽ sau 5-10 năm nữa? :)


2
Không phải hầu hết các vấn đề này đã được giải quyết bằng các biểu tượng gỡ lỗi? Không phải là nó sẽ có hiệu suất (vì nội tuyến và tối ưu hóa mà bạn đã đề cập), nhưng bạn có thể cho phép khả năng phản chiếu bằng cách thực hiện bất kỳ biểu tượng gỡ lỗi nào.
cdleary

2
Một điều khác về điểm đầu tiên của bạn: theo như tôi biết, không ai cố gắng thêm sự phản chiếu vào việc triển khai C ++. Không có kinh nghiệm tốt với nó. Ủy ban có lẽ sẽ miễn cưỡng đi đầu, đặc biệt là sau exportvector<bool>.
David Thornley

18
Tôi đồng ý rằng C ++ không nên có thời gian phản ánh. Nhưng phản xạ thời gian biên dịch có một vài vấn đề ở trên và có thể được sử dụng cho ai đó để xây dựng phản xạ thời gian chạy trên các lớp cụ thể nếu họ chọn. Có thể truy cập loại và tên và các tính năng của phương thức thứ n và cha mẹ thứ n của một lớp thông qua một mẫu? Và có được số lượng như vậy tại thời gian biên dịch? Sẽ làm cho phản xạ tự động dựa trên CRTP có thể thực hiện được, trong khi không ai trả tiền cho những gì họ không sử dụng.
Yakk - Adam Nevraumont

15
Điểm thứ ba của bạn là ở nhiều khía cạnh quan trọng nhất: C ++ được dự định phù hợp để viết mã độc lập trên các nền tảng mà bộ nhớ tốn tiền; nếu loại bỏ một số mã không sử dụng sẽ cho phép một chương trình phù hợp với một vi điều khiển có giá $ 2,00, thay vì một mã có giá $ 2,50 và nếu mã đang ở mức 1.000.000 đơn vị, loại bỏ mã đó có thể tiết kiệm được $ 500,000. Không có sự phản ánh, phân tích tĩnh thường có thể xác định 90% + mã không thể truy cập được; nếu Reflection được cho phép, bất cứ điều gì có thể đạt được thông qua Reflection phải được cho là có thể tiếp cận được, ngay cả khi 90% trong số đó không thể đạt được.
supercat

2
có chắc chắn là một cái gì đó có thể được cải thiện một cách dễ dàng bởi các Comitee, nó là để cuối cùng nói màu đen trắng mà typeinfo's name()chức năng phải trả lại cái tên đó được gõ vào bởi các lập trình viên và không phải cái gì không xác định. Và cung cấp cho chúng tôi một bộ xâu chuỗi cho các điều tra viên. Điều này thực sự quan trọng đối với việc tuần tự hóa /
khử lưu huỳnh

38

Sự phản chiếu đòi hỏi một số siêu dữ liệu về các loại được lưu trữ ở đâu đó có thể được truy vấn. Do C ++ biên dịch thành mã máy gốc và trải qua những thay đổi lớn do tối ưu hóa, nên chế độ xem ứng dụng ở mức độ cao bị mất khá nhiều trong quá trình biên dịch, do đó, không thể truy vấn chúng trong thời gian chạy. Java và .NET sử dụng biểu diễn mức rất cao trong mã nhị phân cho các máy ảo làm cho mức độ phản chiếu này có thể. Tuy nhiên, trong một số triển khai C ++, có một thứ gọi là Thông tin loại thời gian chạy (RTTI) có thể được coi là phiên bản rút gọn của sự phản chiếu.


15
RTTI nằm trong tiêu chuẩn C ++.
Daniel Earwicker

1
Nhưng không phải tất cả các triển khai C ++ đều là tiêu chuẩn. Tôi đã thấy các triển khai không hỗ trợ RTTI.
Mehrdad Afshari

3
Và hầu hết các triển khai hỗ trợ RTTI cũng hỗ trợ tắt nó thông qua các tùy chọn trình biên dịch.
Michael Kohne

21

Tất cả các ngôn ngữ không nên cố gắng kết hợp mọi tính năng của mọi ngôn ngữ khác.

C ++ về cơ bản là một trình biên dịch macro rất, rất tinh vi. Nó KHÔNG (theo nghĩa truyền thống) là một ngôn ngữ cấp cao như C #, Java, Objective-C, Smalltalk, v.v.

Thật tốt khi có các công cụ khác nhau cho các công việc khác nhau. Nếu chúng ta chỉ có búa, tất cả mọi thứ sẽ trông giống như đinh, v.v. Có ngôn ngữ kịch bản là hữu ích cho một số công việc và ngôn ngữ OO phản chiếu (Java, Obj-C, C #) hữu ích cho một loại công việc khác và siêu các ngôn ngữ gần gũi với máy móc hiệu quả rất hữu ích cho một loại công việc khác (C ++, C, Trình biên dịch).

C ++ thực hiện một công việc tuyệt vời là mở rộng công nghệ Trình biên dịch lên mức quản lý phức tạp đáng kinh ngạc và trừu tượng hóa để làm cho việc lập trình lớn hơn, các nhiệm vụ phức tạp hơn có thể thực hiện được cho con người. Nhưng nó không nhất thiết là một ngôn ngữ phù hợp nhất cho những người đang tiếp cận vấn đề của họ từ góc độ cấp cao hoàn toàn (Lisp, Smalltalk, Java, C #). Nếu bạn cần một ngôn ngữ có các tính năng đó để triển khai tốt nhất giải pháp cho các vấn đề của mình, thì xin cảm ơn những người đã tạo ra những ngôn ngữ đó cho tất cả chúng ta sử dụng!

Nhưng C ++ dành cho những người, vì bất kỳ lý do gì, cần phải có mối tương quan chặt chẽ giữa mã của họ và hoạt động của máy bên dưới. Cho dù hiệu quả của nó, hoặc trình điều khiển thiết bị lập trình, hoặc tương tác với các dịch vụ HĐH cấp thấp hơn, hoặc bất cứ điều gì, C ++ đều phù hợp hơn với các tác vụ đó.

C #, Java, Objective-C đều yêu cầu một hệ thống thời gian chạy lớn hơn, phong phú hơn nhiều để hỗ trợ thực hiện chúng. Thời gian chạy đó phải được gửi đến hệ thống được đề cập - được cài đặt sẵn để hỗ trợ hoạt động của phần mềm của bạn. Và lớp đó phải được duy trì cho các hệ thống đích khác nhau, được tùy chỉnh bởi MỘT SỐ NGÔN NGỮ KHÁC để làm cho nó hoạt động trên nền tảng đó. Và lớp giữa đó - lớp thích ứng giữa HĐH máy chủ và mã của bạn - thời gian chạy, hầu như luôn được viết bằng ngôn ngữ như C hoặc C ++, trong đó hiệu quả là số 1, trong đó có thể hiểu được sự tương tác chính xác giữa phần mềm và phần cứng hiểu và thao tác để đạt được tối đa.

Tôi yêu Smalltalk, Objective-C và có một hệ thống thời gian chạy phong phú với sự phản chiếu, siêu dữ liệu, bộ sưu tập rác, v.v. Mã tuyệt vời có thể được viết để tận dụng các tiện ích này! Nhưng đó đơn giản chỉ là một lớp cao hơn trên ngăn xếp, một lớp phải nằm trên các lớp thấp hơn, cuối cùng chính chúng phải nằm trên HĐH và phần cứng. Và chúng ta sẽ luôn cần một ngôn ngữ phù hợp nhất để xây dựng lớp đó: C ++ / C / Assembler.

Phụ lục: C ++ 11/14 đang tiếp tục mở rộng khả năng C ++ để hỗ trợ các hệ thống và trừu tượng cấp cao hơn. Luồng, đồng bộ hóa, mô hình bộ nhớ chính xác, định nghĩa máy trừu tượng chính xác hơn đang cho phép các nhà phát triển C ++ đạt được nhiều khái niệm trừu tượng cấp cao mà một số ngôn ngữ chỉ cấp cao này sử dụng để có miền độc quyền, trong khi tiếp tục cung cấp gần gũi hiệu suất kim loại và khả năng dự đoán tuyệt vời (tức là hệ thống con thời gian chạy tối thiểu). Có lẽ các phương tiện phản chiếu sẽ được kích hoạt có chọn lọc trong phiên bản C ++ trong tương lai, cho những ai muốn nó - hoặc có lẽ một thư viện sẽ cung cấp các dịch vụ thời gian chạy như vậy (có thể có ngay bây giờ hoặc bắt đầu một trong số đó?).


Quan điểm của bạn về thời gian chạy của một ngôn ngữ phải được biên dịch bằng ngôn ngữ khác là không đúng trong trường hợp của Objective-C, vì thời gian chạy của nó được viết bằng C (mà Objective-C là siêu ngôn ngữ).
Richard J. Ross III

Đó là một sự khác biệt không có sự khác biệt. Nó có gì khác biệt, khi cuối cùng, hệ thống con thời gian chạy mà Objective-C sử dụng trên thực tế không được viết bằng Objective-C, mà là bằng C?
Mordachai

3
Tôi xin lỗi; nhưng miễn là bạn liên kết nó đúng cách, bạn có thể biên dịch chương trình object-c trong C, thực tế tôi đã làm nó ở đây: stackoverflow.com/a/10290255/427309 . Toàn bộ tuyên bố trên của bạn là sai. Thời gian chạy hoàn toàn có thể truy cập thông qua C, và một trong những điều làm cho nó trở thành một ngôn ngữ động mạnh mẽ như vậy.
Richard J. Ross III

1
"Thời gian chạy C" chỉ là một thư viện động chứa mã cho thư viện chuẩn C. Tương tự cho "thời gian chạy C ++". Nó hoàn toàn khác với một hệ thống thời gian chạy giống như của Objective-C. Ngoài ra ... trong khi tôi cho rằng về mặt kỹ thuật bạn có thể sử dụng thời gian chạy Objective-C trong C, thì đó vẫn chỉ là chương trình C sử dụng thời gian chạy Objective-C - bạn không thể biên dịch chương trình Objective-C thực tế trong C.
celticminstrel

2
Atomics ++ 11 có một mô hình bộ nhớ + C làm cho nó nhiều hơn như một nhà lắp ráp cầm tay. Đó không phải là những thứ cấp cao, chúng là những thứ cấp thấp mà C ++ trước đây thiếu hỗ trợ di động. Nhưng lượng UB trong C ++ nếu bạn làm bất cứ điều gì sai khiến nó không giống với các ngôn ngữ dựa trên VM như Java và cũng không giống với bất kỳ ngôn ngữ lắp ráp cụ thể nào. ví dụ: tràn tràn đã ký hoàn toàn là UB trong nguồn C ++ và trình biên dịch có thể tối ưu hóa dựa trên thực tế đó ngay cả khi biên dịch cho phép x86, nhưng trong hầu hết tất cả các nền tảng, nó sẽ chỉ bao quanh. C ++ hiện đại rất xa với ngôn ngữ lắp ráp di động.
Peter Cordes

11

Nếu bạn thực sự muốn hiểu các quyết định thiết kế xung quanh C ++, hãy tìm một bản sao của Hướng dẫn tham khảo C ++ được chú thích của Ellis và Stroustrup. Nó KHÔNG cập nhật với tiêu chuẩn mới nhất, nhưng nó đi qua tiêu chuẩn ban đầu và giải thích cách mọi thứ hoạt động và thường xuyên, làm thế nào họ có được theo cách đó.


6
Đồng thời thiết kế và phát triển C ++ của Stroustrup
James Hopkin

9

Sự phản ánh cho các ngôn ngữ có nó là về bao nhiêu mã nguồn mà trình biên dịch sẵn sàng để lại trong mã đối tượng của bạn để cho phép phản chiếu và bao nhiêu máy móc phân tích có sẵn để diễn giải thông tin phản ánh đó. Trừ khi trình biên dịch giữ tất cả các mã nguồn xung quanh, sự phản chiếu sẽ bị hạn chế trong khả năng phân tích các sự kiện có sẵn về mã nguồn.

Trình biên dịch C ++ không giữ bất cứ thứ gì xung quanh (tốt, bỏ qua RTTI), vì vậy bạn không nhận được phản ánh trong ngôn ngữ. (Trình biên dịch Java và C # chỉ giữ lớp, tên phương thức và kiểu trả về, vì vậy bạn có được một chút dữ liệu phản chiếu, nhưng bạn không thể kiểm tra biểu thức hoặc cấu trúc chương trình và điều đó có nghĩa là ngay cả trong các ngôn ngữ "hỗ trợ phản chiếu" đó thông tin bạn có thể nhận được khá thưa thớt và do đó bạn thực sự không thể phân tích nhiều).

Nhưng bạn có thể bước ra ngoài ngôn ngữ và có được khả năng phản ánh đầy đủ. Câu trả lời cho một cuộc thảo luận tràn ngăn xếp khác về sự phản chiếu trong C thảo luận về điều này.


7

Sự phản chiếu có thể và đã được thực hiện trong c ++ trước đây.

Đây không phải là một tính năng c ++ riêng vì nó có chi phí lớn (bộ nhớ và tốc độ) không nên được đặt theo mặc định bởi ngôn ngữ - ngôn ngữ được định hướng "hiệu suất tối đa theo mặc định".

Vì bạn không nên trả tiền cho những gì bạn không cần, và như bạn tự nói, nó cần nhiều hơn cho các biên tập viên so với các ứng dụng khác, nên nó chỉ được thực hiện ở nơi bạn cần chứ không phải "ép buộc" với tất cả mã ( bạn không cần phản ánh tất cả dữ liệu bạn sẽ làm việc trong trình chỉnh sửa hoặc ứng dụng tương tự khác).


3
và bạn không gửi biểu tượng vì nó sẽ cho phép khách hàng / đối thủ của bạn nhìn vào mã của bạn ... điều này thường được coi là một điều xấu.
gbjbaanb

Bạn nói đúng, tôi thậm chí không quan tâm đến vấn đề giải trình mã :)
Klaim

6

Lý do C ++ không có phản ánh là vì điều này sẽ yêu cầu trình biên dịch thêm thông tin ký hiệu vào các tệp đối tượng, giống như các loại thành viên có loại, thông tin về các thành viên, về các hàm và mọi thứ. Điều này về cơ bản sẽ bao gồm các tệp vô dụng, vì thông tin được gửi bởi các khai báo sau đó sẽ được đọc từ các tệp đối tượng đó (các mô-đun sau đó). Trong C ++, một định nghĩa kiểu có thể xuất hiện nhiều lần trong một chương trình bằng cách bao gồm các tiêu đề tương ứng (với điều kiện là tất cả các định nghĩa đó đều giống nhau), do đó, sẽ phải quyết định đặt thông tin về loại đó ở đâu, giống như đặt tên cho một biến chứng ở đây. Việc tối ưu hóa mạnh mẽ được thực hiện bởi trình biên dịch C ++, có thể tối ưu hóa hàng tá các mẫu tức thời của lớp, là một điểm mạnh khác. Điều đó là có thể, nhưng vì C ++ tương thích với C,


1
Tôi không hiểu làm thế nào tối ưu hóa tích cực của nhà biên dịch là một điểm mạnh. Bạn có thể xây dựng? Nếu trình liên kết có thể loại bỏ các định nghĩa hàm nội tuyến trùng lặp, thì vấn đề với thông tin phản ánh trùng lặp là gì? Không phải thông tin biểu tượng được thêm vào tệp đối tượng, cho trình gỡ lỗi?
Rob Kennedy

1
Vấn đề là thông tin phản ánh của bạn có thể không hợp lệ. Nếu trình biên dịch loại bỏ 80% định nghĩa lớp của bạn, siêu dữ liệu phản chiếu của bạn sẽ nói gì? Trong C # và Java, ngôn ngữ đảm bảo rằng nếu bạn định nghĩa một lớp, nó sẽ được xác định. C ++ cho phép trình biên dịch tối ưu hóa nó đi.
jalf

1
@Rob, tối ưu hóa là một điểm khác, không gắn liền với biến chứng nhiều lớp. Xem bình luận của @ jalf (và câu trả lời của anh ấy) để biết ý của tôi.
Julian Schaub - litb

4
Nếu tôi khởi tạo phản ánh <T>, thì đừng vứt bỏ bất kỳ thông tin nào của T. Đây dường như không phải là một vấn đề không thể giải quyết.
Joseph Garvin

3

Có rất nhiều trường hợp sử dụng sự phản chiếu trong C ++ mà không thể giải quyết thỏa đáng bằng cách sử dụng các cấu trúc thời gian biên dịch như lập trình meta mẫu.

N3340 đề xuất các con trỏ phong phú như một cách để giới thiệu sự phản chiếu trong C ++. Trong số những thứ khác, nó giải quyết vấn đề không trả tiền cho một tính năng trừ khi bạn sử dụng nó.


2

Theo Alistair Cockburn, việc phân nhóm không thể được đảm bảo trong môi trường phản chiếu .

Sự phản chiếu có liên quan nhiều hơn đến các hệ thống gõ tiềm ẩn. Trong C ++, bạn biết loại bạn đã có và bạn biết bạn có thể làm gì với nó.


Tổng quát hơn, khả năng kiểm tra sự tồn tại của một tính năng không tồn tại mà không giới thiệu Hành vi không xác định cho phép thêm tính năng đó vào phiên bản mới hơn của một lớp sẽ thay đổi hành vi được xác định rõ của các chương trình có sẵn và sẽ do đó, không thể đảm bảo rằng việc thêm tính năng đó sẽ không "phá vỡ" thứ gì đó.
supercat

2

Sự phản chiếu có thể là tùy chọn, giống như một chỉ thị tiền xử lý. Cái gì đó như

#pragma enable reflection

Bằng cách đó, chúng ta có thể có những điều tốt nhất của cả hai thế giới, với những thư viện pragma này sẽ được tạo ra mà không có sự phản chiếu (không có bất kỳ chi phí nào như đã thảo luận), sau đó sẽ tùy thuộc vào nhà phát triển dù họ muốn tốc độ hay dễ sử dụng.


2

Nếu C ++ có thể có:

  • dữ liệu thành viên lớp cho tên biến, loại biến và công cụ constsửa đổi
  • một hàm đối số iterator (chỉ vị trí thay vì tên)
  • dữ liệu thành viên lớp cho tên hàm, kiểu trả về và bộ constsửa đổi
  • danh sách các lớp cha (theo thứ tự như được định nghĩa)
  • dữ liệu cho các thành viên mẫu và các lớp cha; mẫu mở rộng (có nghĩa là loại thực tế sẽ có sẵn cho API phản chiếu chứ không phải 'thông tin mẫu về cách đến đó')

Điều đó đủ để tạo ra các thư viện rất dễ sử dụng ở mấu chốt của quá trình xử lý dữ liệu không điển hình vốn rất phổ biến trong các ứng dụng web và cơ sở dữ liệu ngày nay (tất cả các orms, cơ chế nhắn tin, trình phân tích cú pháp xml / json, tuần tự hóa dữ liệu, v.v.).

Ví dụ: thông tin cơ bản được Q_PROPERTYmacro hỗ trợ (một phần của Khung Qt) http://qt.nokia.com/doc/4.5/properIES.html được mở rộng để bao quát các phương thức lớp và e) - sẽ có lợi phi thường cho C ++ và cho cộng đồng phần mềm nói chung.

Chắc chắn sự phản ánh mà tôi đang đề cập sẽ không đề cập đến ý nghĩa ngữ nghĩa hoặc các vấn đề phức tạp hơn (như số dòng mã nguồn nhận xét, phân tích luồng dữ liệu, v.v.) - nhưng tôi không nghĩ chúng là một phần của tiêu chuẩn ngôn ngữ.


@Vlad: Có, nếu thêm một tính năng hỗ trợ sự phản chiếu cho ngôn ngữ, bạn sẽ có được sự phản chiếu trong ngôn ngữ. Điều này chỉ có khả năng xảy ra nếu ủy ban ngôn ngữ đồng ý và tôi nghĩ rằng họ chưa có từ năm 2011, và tôi nghi ngờ sẽ có một tiêu chuẩn C ++ khác trước năm 2020 sau Công nguyên. Vì vậy, suy nghĩ tốt đẹp. Trong khi đó, nếu bạn muốn đạt được tiến bộ, bạn có thể phải bước ra ngoài C ++.
Ira Baxter


0

Phản ánh trong C ++, tôi tin là cực kỳ quan trọng nếu C ++ được sử dụng làm ngôn ngữ để truy cập cơ sở dữ liệu, xử lý phiên Web / phát triển GUI và GUI. Việc thiếu sự phản chiếu sẽ ngăn các ORM (như Hibernate hoặc LINQ), các trình phân tích cú pháp XML và JSON tạo ra các lớp, tuần tự hóa dữ liệu và nhiều thứ khác (trong đó dữ liệu ban đầu phải được sử dụng để tạo một thể hiện của một lớp).

Một công tắc thời gian biên dịch có sẵn cho nhà phát triển phần mềm trong quá trình xây dựng có thể được sử dụng để loại bỏ điều này 'bạn phải trả cho những gì bạn sử dụng'.

Tôi là một nhà phát triển công ty không cần sự phản chiếu để đọc dữ liệu từ một cổng nối tiếp - vậy thì không nên sử dụng công tắc. Nhưng là một nhà phát triển cơ sở dữ liệu muốn tiếp tục sử dụng C ++, tôi liên tục bị theo dõi với một mã khủng khiếp, khó duy trì, ánh xạ dữ liệu giữa các thành viên dữ liệu và cấu trúc cơ sở dữ liệu.

Cả tuần tự Boost và cơ chế khác đều không thực sự giải quyết được sự phản chiếu - nó phải được trình biên dịch thực hiện - và một khi nó được thực hiện, C ++ sẽ lại được sử dụng trong các trường học và được sử dụng trong phần mềm xử lý dữ liệu

Đối với tôi vấn đề này # 1 (và nguyên thủy phân luồng naitive là vấn đề # 2).


4
Ai nói C ++ sẽ được sử dụng làm ngôn ngữ cho DB Access, phiên bản web hnadling hoặc gui dev? Có rất nhiều ngôn ngữ tốt hơn để sử dụng cho loại công cụ đó. Và một công tắc thời gian biên dịch sẽ không giải quyết được vấn đề. Thông thường, quyết định kích hoạt hoặc vô hiệu hóa phản chiếu sẽ không dựa trên cơ sở mỗi tệp. Nó có thể hoạt động nếu nó có thể được kích hoạt trên các loại cá nhân. Nếu lập trình viên có thể chỉ định với một thuộc tính hoặc tương tự khi xác định một loại, liệu có nên tạo siêu dữ liệu phản chiếu cho nó hay không. Nhưng một chuyển đổi toàn cầu? Bạn sẽ làm tê liệt 90% số tiền chỉ để làm cho 10% đơn giản hơn.
jalf

Sau đó, nếu tôi muốn một chương trình đa nền tảng và có quyền truy cập vào gui, tôi nên sử dụng cái gì? Các java không linh hoạt swing? Các cửa sổ chỉ C #? Nhưng sự thật nên được nói, và sự thật là có rất nhiều chương trình được biên dịch theo mã thực thi, và cung cấp giao diện gui và truy cập vào cơ sở dữ liệu, vì vậy họ phải sử dụng một số cơ sở dữ liệu và hỗ trợ gui ... Và chúng không được ' t sử dụng QT. (đáng lẽ nó phải được đặt tên là MT (bộ công cụ quái vật))
Coyote21

1
@ Coyote21: C # không chỉ dành cho Windows trong nhiều năm. (Mặc dù tôi không phải là fan hâm mộ của Mono, nhưng nó hoạt động đủ tốt cho hầu hết mọi thứ.) Và Swing không phải là bộ công cụ GUI duy nhất cho Java. Sự thật mà nói, một trong hai sẽ là một lựa chọn tốt hơn nếu bạn muốn đa nền tảng. C ++ là khá nhiều luôn luôn có các phần cụ thể nền tảng ở đây hoặc ở đó nếu bạn đang làm bất cứ điều gì không tầm thường.
cHao

Không có lý do tại sao bạn cần phản ánh cho ORM. Bạn có thể đạt được tất cả điều đó với các mẫu. Có một loạt các khung cung cấp ORM cho C ++.
MrFox

0

Về cơ bản là vì nó là "tùy chọn thêm". Nhiều người chọn C ++ trên các ngôn ngữ như Java và C # để họ có quyền kiểm soát nhiều hơn đối với đầu ra của trình biên dịch, ví dụ: chương trình nhỏ hơn và / hoặc nhanh hơn.

Nếu bạn chọn thêm phản chiếu, có nhiều giải pháp khác nhau .

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.