Tại sao C không được coi là ngôn ngữ 'hướng đối tượng'?


92

Dường như C có các đối tượng gần giống như 'cấu trúc' có thể được coi là đối tượng (theo cách cấp cao mà chúng ta thường nghĩ).

Ngoài ra, bản thân các tệp C về cơ bản là các "mô-đun" riêng biệt, phải không? Vậy thì các mô-đun cũng giống như 'đối tượng' phải không? Tôi bối rối không hiểu tại sao C, có vẻ rất giống với C ++, được coi là ngôn ngữ "thủ tục" cấp thấp trong khi C ++ là "hướng đối tượng" cấp cao

* chỉnh sửa: (làm rõ) tại sao và ở đâu, đường được vẽ, cho 'đối tượng' là gì và không?


40
Tất cả - tại sao các phiếu giảm? Đó là một câu hỏi cơ bản nhưng không phải là một câu hỏi xấu.
Jon Hopkins

7
Bạn có thể sử dụng các nguyên tắc OO một cách hiệu quả trong C (và những người viết mã C tốt thường làm), nhưng ngôn ngữ không được xây dựng xung quanh làm cho nó dễ dàng, vì nhiều ngôn ngữ gần đây hơn.
asveikau

5
C đơn giản là có một cách tiếp cận khác, đơn giản hơn và (thành thật hơn) được xác định tốt hơn (ít nhất là trong cộng đồng nguồn mở) để trừu tượng hóa dữ liệu. C ++ có xu hướng trở thành một thế lực trừu tượng và cho phép nhiều thứ tuyệt vời, nhưng đi kèm với chi phí phải hiểu làm thế nào để [không] sử dụng chúng đúng cách, điều thường xuyên hơn là không thiếu trong các chương trình phổ biến. Xem câu trả lời đầy đủ của tôi để biết thêm chi tiết.
Yam Marcovic

1
Một thời gian ngắn: Structs không thể có phương pháp. (Con trỏ tới một chức năng không hoàn toàn cắt nó).
SF.

1
Có thể thực hiện lập trình dựa trên đối tượng trong C, với một số khó khăn. Nhưng điều đó không làm cho nó hướng đối tượng .
Nêm

Câu trả lời:


101

Dường như C có các đối tượng gần giống như 'cấu trúc' có thể được coi là các đối tượng

Chúng ta hãy cùng nhau và tôi đọc qua trang Wikipedia về lập trình hướng đối tượng và kiểm tra các tính năng của các cấu trúc kiểu C tương ứng với những gì được coi là phong cách hướng đối tượng theo truyền thống:

(OOP) là mô hình lập trình sử dụng "đối tượng" - cấu trúc dữ liệu bao gồm các trường dữ liệu và phương thức cùng với các tương tác của chúng

Các cấu trúc C có bao gồm các trường và phương thức cùng với các tương tác của chúng không? Không.

Các kỹ thuật lập trình có thể bao gồm các tính năng như trừu tượng hóa dữ liệu, đóng gói, nhắn tin, mô đun hóa, đa hình và kế thừa.

Các cấu trúc C có thực hiện bất kỳ điều nào trong những điều này theo cách "hạng nhất" không? Không. Ngôn ngữ hoạt động chống lại bạn mỗi bước trên đường.

cách tiếp cận hướng đối tượng khuyến khích lập trình viên đặt dữ liệu ở nơi mà phần còn lại của chương trình không thể truy cập trực tiếp

Do C structs làm điều này? Không.

Một chương trình hướng đối tượng thường sẽ chứa các loại đối tượng khác nhau, mỗi loại tương ứng với một loại dữ liệu phức tạp cụ thể được quản lý hoặc có thể là đối tượng hoặc khái niệm trong thế giới thực

Do C structs làm điều này? Đúng.

Các đối tượng có thể được coi là gói dữ liệu của họ trong một tập hợp các hàm được thiết kế để đảm bảo rằng dữ liệu được sử dụng một cách thích hợp

Không.

mỗi đối tượng có khả năng nhận tin nhắn, xử lý dữ liệu và gửi tin nhắn đến các đối tượng khác

Một cấu trúc có thể tự gửi và nhận tin nhắn? Không. Nó có thể xử lý dữ liệu không? Không.

Các cấu trúc dữ liệu OOP có xu hướng "mang các toán tử riêng của họ đi theo họ"

Điều này xảy ra trong C? Không.

Công văn động ... Đóng gói ... Đa hình phụ ... Kế thừa đối tượng ... Đệ quy mở ... Các lớp đối tượng ... Thể hiện của các lớp ... Các phương thức tác động lên các đối tượng đính kèm ... Thông điệp truyền qua .. Trừu tượng

Có bất kỳ tính năng nào của các cấu trúc C không? Không.

Chính xác những đặc điểm nào của cấu trúc mà bạn nghĩ là "hướng đối tượng"? Bởi vì tôi không thể tìm thấy bất kỳ thứ gì khác ngoài thực tế là các cấu trúc xác định các loại .

Bây giờ, tất nhiên bạn có thể tạo các cấu trúc có các trường là con trỏ tới các hàm. Bạn có thể tạo các cấu trúc có các trường là các con trỏ tới các mảng của các con trỏ hàm, tương ứng với các bảng phương thức ảo. Và như vậy. Tất nhiên bạn có thể mô phỏng C ++ trong C. Nhưng đó là một cách rất không thành ngữ để lập trình trong C; bạn nên sử dụng C ++.

Ngoài ra, bản thân các tệp C về cơ bản là các "mô-đun" riêng biệt, phải không? Vậy thì các mô-đun cũng giống như 'đối tượng' phải không?

Một lần nữa, những đặc điểm nào của các mô-đun mà bạn nghĩ đến khiến chúng hoạt động như các đối tượng? Các mô-đun có hỗ trợ trừu tượng hóa, đóng gói, nhắn tin, mô đun hóa, đa hình và kế thừa không?

Trừu tượng và đóng gói là khá yếu. Rõ ràng các mô-đun là mô-đun; đó là lý do tại sao chúng được gọi là mô-đun. Nhắn tin? Chỉ theo nghĩa là một cuộc gọi phương thức là một thông điệp và các mô-đun có thể chứa các phương thức. Đa hình? Không. Di sản? Không. Các mô-đun là ứng cử viên khá yếu cho "đối tượng".


15
Tôi không đồng ý rằng "giả lập C ++" (thuật ngữ của bạn) không phải là thành ngữ C. Một ví dụ ngược lại sẽ là cách một nhân hệ điều hành thường thực hiện các hoạt động của tệp - lấy Linux làm ví dụ, trong đó bạn có cấu trúc đầy đủ các con trỏ hàm. Chúng có thể là một số thành ngữ "đặc thù miền" (giới hạn trong việc viết trình điều khiển trên * nix, nói), nhưng chúng có thể nhận ra và thực hiện công việc đủ sạch cho một số mục đích. Ngoài ra còn có một số ví dụ về các thư viện chế độ người dùng thực hiện một số khái niệm về OO đủ tốt; lấy Gtk + và các thư viện phụ thuộc vào. Gọi nó là hacky và bạn có thể đúng, nhưng những thứ này không tệ khi làm việc với
asveikau

5
@asveikau: Không phải ý tưởng cho rằng một thực tiễn là bất thường (ngay cả khi không nghe thấy) và "hacky" có nghĩa là, theo định nghĩa, nó không phải là thành ngữ?
Adam Robinson

19
@asveikau: Chắc chắn, có những điều bạn có thể làm để làm cho các chương trình C trở nên phong cách hơn. Nhưng như bạn nói, nó đòi hỏi kỷ luật để làm như vậy; bản thân các tính năng ngôn ngữ không tự nhiên dẫn bạn đến việc đóng gói, đa hình, kế thừa lớp, v.v. Thay vào đó, nhà phát triển có thể áp đặt mô hình đó lên ngôn ngữ. Điều đó không có nghĩa là các cấu trúc là logic tương tự như các đối tượng. Heck, bạn cũng có thể lập trình theo kiểu OO trong Lisp, nhưng điều đó không có nghĩa là các ô cons là đối tượng.
Eric Lippert

3
@asveikau, tôi có thể đề nghị rằng cách giải thích (thành ngữ) của bạn về "thành ngữ" là "của chính mình" là ... bình dị không? :)
Stewol

8
@BillK: Structs không thể chứa mã trong C. Structs có thể chứa các con trỏ hàm , là dữ liệu . Chức năng con trỏ không . là một tạo tác văn bản được tạo bởi một lập trình viên.
Eric Lippert

46

Từ khóa là "định hướng", không phải "đối tượng". Ngay cả mã C ++ sử dụng các đối tượng nhưng sử dụng chúng như structs cũng không hướng đối tượng .

Cả C và C ++ đều có thể thực hiện OOP (ngoài việc không kiểm soát truy cập trong C), nhưng cú pháp để thực hiện trong C là bất tiện (để nói là ít nhất), trong khi cú pháp trong C ++ khiến nó rất hấp dẫn. C được định hướng theo thủ tục, trong khi C ++ được định hướng cho các đối tượng, mặc dù các khả năng cốt lõi gần như giống hệt nhau về vấn đề đó.

Mã sử ​​dụng các đối tượng để thực hiện các thiết kế chỉ có thể được thực hiện với các đối tượng (thường có nghĩa là lợi dụng tính đa hình) là mã hướng đối tượng. Mã sử ​​dụng các đối tượng ít hơn một túi dữ liệu, thậm chí sử dụng tính kế thừa trong ngôn ngữ hướng đối tượng, thực sự chỉ là mã thủ tục phức tạp hơn mức cần thiết. Mã trong C sử dụng các con trỏ hàm được thay đổi xung quanh trong thời gian chạy với các cấu trúc chứa đầy dữ liệu là loại đa hình và có thể được gọi là "hướng đối tượng", ngay cả trong ngôn ngữ được định hướng theo thủ tục.


2
+1 Để chỉ điểm C của chúng tôi có thể là OO. Nó không thuận tiện, nhưng nó có thể được thực hiện.
dietbuddha

Việc tạo các đối tượng trong VBA sẽ dễ dàng hơn, nhưng tôi cũng không coi đó là đối tượng 'định hướng'.
JeffO

VBA tôi gọi là "đối tượng dựa". Nó sử dụng các đối tượng, nhưng không phải là đa hình, và trong một chút công việc tôi đã thực hiện trong đó, tôi không chắc bạn thậm chí có thể thực hiện đa hình cho dù bạn có thử loại nhào lộn mã nào. Về cơ bản, nó là một ngôn ngữ thủ tục với sự đóng gói.
kylben

2
Hầu hết các ngôn ngữ có thể hoạt động như một OO, có chức năng hoặc khá nhiều phong cách ngôn ngữ. sự khác biệt là "Định hướng" và tôi chưa bao giờ nghe thấy nó theo cách đó trước đây. Tôi ước tôi có thể bỏ phiếu này 3 lần và chấp nhận nó, đó là câu trả lời đúng.
Bill K

1
@kylben Sẽ không quá căng để lưu trữ mã SQL trong bảng sau đó trích xuất và thực thi (biến bảng thành đối tượng của bạn) Đây sẽ là một thử nghiệm thú vị. Trên thực tế, nó có một chút hấp dẫn ...
Bill K

19

Dựa trên các hiệu trưởng cấp cao nhất:

Một đối tượng là sự đóng gói dữ liệu và hành vi theo cách liên kết với nhau để chúng hoạt động như một tổng thể có thể được khởi tạo nhiều lần và hoạt động như một hộp đen nếu bạn biết giao diện bên ngoài.

Các cấu trúc chứa dữ liệu nhưng không có hành vi và do đó không thể được coi là đối tượng.

Các mô-đun chứa cả hành vi và dữ liệu nhưng không được gói gọn theo cách hai cái đó có liên quan và chắc chắn không thể được khởi tạo nhiều lần.

Và đó là trước khi bạn có được sự kế thừa và đa hình ...


Làm thế nào đến hành vi và dữ liệu trong các mô-đun không liên quan? Về cơ bản, các chức năng thành viên không phải là 'hành vi' trên dữ liệu tồn tại trong mô-đun?
Dark Templar

4
Vấn đề là chúng không được gói gọn, không phải chúng không liên quan.
Eoin Carroll

Trên thực tế các đối tượng được tập trung chủ yếu xung quanh hành vi , không phải dữ liệu. Dữ liệu là / nên là một công dân hạng hai trong OOP. Cấu trúc, thay vào đó tập trung vào dữ liệu và không có hành vi.
Sklivvz

1
@Dark Templar - Những gì Eoin nói ... Đó là bản chất của mối quan hệ. Tôi có thể thấy bạn đến từ đâu - bạn chắc chắn có thể sử dụng Structs trong một mô-đun theo cách mà nó mô phỏng một số yếu tố rất cơ bản của OO nhưng phần lớn những gì bạn đang làm sẽ dựa vào lập trình viên gắn bó với một bộ của các quy tắc tự áp đặt hơn là có ngôn ngữ thực thi nó. Và tại sao bạn lại bận tâm? Bạn không nhận được bất kỳ lợi ích nào của OO - chẳng hạn như không có quyền thừa kế - và bạn đang tự giới hạn bản thân mình.
Jon Hopkins

Đây là một câu trả lời tốt hơn so với câu trả lời đúng.
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

6

"cấu trúc" chỉ là dữ liệu. Thử nghiệm nhanh và bẩn thông thường về "hướng đối tượng" là: "Có cấu trúc nào cho phép mã và dữ liệu được gói gọn thành một đơn vị không?". C thất bại, và do đó là thủ tục. C ++ vượt qua bài kiểm tra đó.


6
Có cách giải quyết, cấu trúc có thể có con trỏ hàm tĩnh đến các hàm thành viên. Họ sẽ cần thiscon trỏ rõ ràng , nhưng trong trường hợp đó, dữ liệu và phương tiện để xử lý dữ liệu sẽ được gói gọn bên trong cấu trúc.
Coder

@Brian Knoblauch: nhưng bản thân tệp C không phải là sự đóng gói dữ liệu và mã ??
Dark Templar

@DarkTemplar Theo một nghĩa nào đó, có, nhưng trừ khi bạn quản lý để tạo các đơn vị dịch thuật, biên dịch chúng và tải chúng vào quy trình đang chạy trong thời gian chạy, điều này sẽ không tốt chút nào.

đơn vị dịch thuật? >. <
Dark Templar

@Dark Templar: Một đơn vị dịch là một tập tin nguồn cộng với bất cứ điều gì #included vào nó, và trừ bất cứ điều gì bị loại bỏ bởi không được có điều kiện bao gồm ( #if, #ifdef, và những thứ tương tự).
David Thornley

5

C, giống như C ++, có khả năng cung cấp Trừu tượng dữ liệu , là một thành ngữ của mô hình lập trình hướng đối tượng tồn tại trước nó.

  • Các cấu trúc C có thể có dữ liệu (và đó là mục đích chính của chúng)
  • Các cấu trúc C cũng có thể định nghĩa các con trỏ hàm là dữ liệu
  • C struct có thể và thường có một tập hợp các chức năng liên kết với chúng, giống như phương pháp, chỉ có này con trỏ không được thông qua ngầm, nhưng bạn phải xác định nó một cách rõ ràng như là đối số đầu tiên cho mỗi phương pháp được thiết kế để xử lý các struct định. C ++ thực hiện điều này tự động cho bạn, cả khi bạn định nghĩagọi các phương thức class / struct.

OOP trong C ++ mở rộng phương tiện cho dữ liệu trừu tượng. Một số người nói rằng nó có hại , trong khi những người khác coi nó là một công cụ tốt khi được sử dụng đúng cách.

  • C ++ làm cho con trỏ này ẩn bằng cách không yêu cầu người dùng chuyển nó vào "các phương thức của lớp / struct" miễn là loại có thể được xác định (ít nhất là một phần).
  • C ++ cho phép bạn hạn chế quyền truy cập vào một số phương thức nhất định (chức năng lớp) và do đó cho phép "lập trình phòng thủ" hoặc "chống chứng ngốc" hơn.
  • C ++ khuyến khích sự trừu tượng bằng cách cung cấp loại an toàn mạnh hơn bằng cách giới thiệu
    1. Các mới điều hành thay vì malloc + dàn diễn viên
    2. Mẫu thay vì con trỏ void
    3. Hàm nội tuyến nhận giá trị được nhập thay vì macro
    4. Được xây dựng trong Đa hình mà bạn không phải tự thực hiện, cho phép bạn tạo phân cấp trừu tượng , hợp đồngchuyên môn .

Tuy nhiên, bạn sẽ tìm thấy nhiều "tin tặc" C đang rao giảng về cách C hoàn toàn có khả năng chỉ cần mức độ trừu tượng phù hợp và cách chi phí được tạo bởi C ++ chỉ khiến họ mất tập trung vào việc giải quyết vấn đề thực tế.

Các mô hình lập trình trừu tượng không hiệu quả trong đó hai năm bạn nhận thấy rằng một số trừu tượng không hiệu quả lắm, nhưng bây giờ tất cả mã của bạn phụ thuộc vào tất cả các mô hình đối tượng đẹp xung quanh nó và bạn không thể sửa nó mà không cần viết lại ứng dụng của mình. -- Linus Torvalds

Những người khác có xu hướng nhìn nó một cách cân bằng hơn, chấp nhận cả những ưu điểm cùng với những nhược điểm.

C giúp bạn dễ dàng tự bắn vào chân mình; C ++ làm cho nó khó hơn, nhưng khi bạn làm điều đó sẽ thổi bay toàn bộ chân của bạn. - Bjarne Stroustrup


2

Bạn cần nhìn vào mặt khác của đồng tiền: C ++.

Trong OOP, chúng tôi nghĩ về một đối tượng trừu tượng (và thiết kế chương trình phù hợp), ví dụ một chiếc xe có thể dừng, tăng tốc, rẽ trái hoặc phải, v.v ... Một cấu trúc với một bó các chức năng đơn giản là không phù hợp với khái niệm.

Ví dụ, với các đối tượng "thực", chúng ta cần ẩn các thành viên hoặc chúng ta cũng có thể có quyền thừa kế với một mối quan hệ "thực" và nhiều hơn nữa.

SAU KHI ĐỌC Ý KIẾN BÊN DƯỚI: Vâng, đúng là (hầu như) mọi thứ đều có thể được thực hiện với C (điều đó luôn đúng), nhưng thoạt nhìn tôi đã nghĩ rằng điều tách biệt c với c ++ là cách bạn nghĩ khi thiết kế chương trình.

Điều duy nhất thực sự tạo ra sự khác biệt là việc áp dụng các chính sách của trình biên dịch . tức là chức năng ảo thuần túy, và như vậy. nhưng câu trả lời này sẽ chỉ liên quan đến các vấn đề kỹ thuật, nhưng tôi nghĩ rằng sự khác biệt chính (như đã đề cập) là cách bạn nghĩ khi viết mã, vì C ++ cung cấp cho bạn một cú pháp được xây dựng tốt hơn để làm những việc đó, thay vì thực hiện OOP trong một cách hơi vụng về trong C.


Không thực sự chắc chắn tại sao một cấu trúc có "gói chức năng" không phù hợp với khái niệm này? +1 cho câu trả lời mặc dù
Dark Templar

1
Ngoài kiểm soát truy cập (riêng tư / được bảo vệ / công khai), mọi thứ khác có thể được thực hiện với các cấu trúc.
Coder

1
@DarkTemplar: Chà, bạn có thể thử mô phỏng OOP bằng C (mọi người thực sự đã viết sách điện tử về chủ đề đó và thực hiện nó trong thế giới thực, mặc dù rất hiếm khi), giống như bạn có thể thử mô phỏng lập trình chức năng trong Java. Nhưng C cung cấp trợ giúp bằng không cho nó, do đó C ngôn ngữ không hướng đối tượng .

1

Bạn tự nói điều đó. Mặc dù C có những thứ giống như các đối tượng, chúng vẫn không phải là các đối tượng và đó là lý do tại sao C không được coi là ngôn ngữ OOP.


1
Chà, tôi đoán câu hỏi là: tại sao và đâu là đường được vẽ cho vật thể là gì và cái gì không?
Templar tối

1

Hướng đối tượng đề cập đến cả một mẫu kiến ​​trúc (hoặc thậm chí là một mẫu meta) và, các ngôn ngữ có các tính năng để giúp triển khai hoặc ủy thác sử dụng mẫu này.

Bạn có thể thực hiện thiết kế "OO" (máy tính để bàn Gnome có lẽ là ví dụ tốt nhất về OO được thực hiện bằng C thuần túy), tôi thậm chí đã thấy điều này được thực hiện với COBOL!

Tuy nhiên, việc có thể thực hiện liều thiết kế OO không tạo ra ngôn ngữ OO. Những người theo chủ nghĩa thuần túy sẽ cho rằng Java và C ++ không thực sự là OO vì bạn không thể ghi đè hoặc kế thừa các "loại" cơ bản như "int" và "char" và, Java không hỗ trợ nhiều kế thừa. Nhưng vì chúng là ngôn ngữ OO được sử dụng rộng rãi nhất và hỗ trợ hầu hết các lập trình viên "thực sự" nhất được trả tiền để tạo mã làm việc coi chúng là ngôn ngữ OO.

Mặt khác, C chỉ hỗ trợ các cấu trúc (cũng như COBOL, Pascal và hàng tá ngôn ngữ thủ tục khác), bạn có thể lập luận rằng hỗ trợ nhiều kế thừa trong đó bạn có thể sử dụng bất kỳ chức năng nào trên bất kỳ phần dữ liệu nào nhưng hầu hết sẽ coi đây là lỗi hơn là một tính năng.


0

Hãy nhìn vào định nghĩa của OO:

  • Nhắn tin
  • Đóng gói
  • Ràng buộc muộn

C cung cấp không ai trong số ba. Đặc biệt, nó không cung cấp Tin nhắn , là thứ quan trọng nhất.


1
Tôi nghĩ rằng tôi phải không đồng ý với điều đó. Bạn chắc chắn có thể nhắn tin bằng C - làm việc với API C khách quan từ C và bạn thấy rằng sâu hơn - và ràng buộc muộn có thể được thực hiện thông qua các con trỏ hàm, nhưng bạn không có nhiều đường cú pháp để ẩn nó. (Đóng gói thực sự dễ dàng trong C; con trỏ đến các loại cấu trúc không hoàn chỉnh thực hiện công việc một cách hoàn hảo.)
Donal Fellows

Kế thừa cũng được coi là quan trọng trong OO và C không làm điều đó. Điều gần nhất để đóng gói trong C là các tệp riêng biệt có thể có các statichàm nội bộ ( ) và các thành viên dữ liệu.
David Thornley

@DonalFellows, thông điệp thực tế truyền trong Objective-C có thể dễ dàng thực hiện dưới dạng macro C99. Điều duy nhất mà trình biên dịch đã thực hiện là nó tạo ra tất cả các cấu trúc cần thiết một cách tĩnh từ một vài dòng mã cấp cao. Hầu hết nếu không phải tất cả các tính năng đều có sẵn từ API C.
qpr

0

Có một số thành phần chính của OO, nhưng các thành phần lớn là phần lớn mã không biết bên trong một đối tượng (họ nhìn thấy giao diện bề mặt, không phải việc triển khai), rằng trạng thái của một đối tượng là một đơn vị được quản lý (nghĩa là khi đối tượng không còn, trạng thái của nó cũng vậy) và khi một số mã gọi một hoạt động trên một đối tượng, họ làm như vậy mà không biết chính xác hoạt động đó là gì hoặc liên quan (tất cả những gì họ làm là theo một mô hình để ném Tin nhắn của người Bỉ trên tường).

C đóng gói chỉ tốt; mã không nhìn thấy định nghĩa của cấu trúc không thể (nhìn nhận) một cách hợp pháp bên trong nó. Tất cả những gì bạn cần làm là đặt một định nghĩa như thế này trong tệp tiêu đề:

struct FooImpl;
typedef struct FooImpl *Foo;

Tất nhiên, sẽ cần một hàm xây dựng Foos (nghĩa là một nhà máy) và sẽ ủy thác một số công việc cho chính đối tượng được phân bổ (nghĩa là thông qua một phương thức xây dựng của nhà xây dựng) và cũng có cách về việc xử lý đối tượng một lần nữa (trong khi cho phép nó dọn sạch thông qua phương thức hủy diệt của nó) nhưng đó là chi tiết.

Việc gửi phương thức (nghĩa là nhắn tin) cũng có thể được thực hiện thông qua quy ước rằng phần tử đầu tiên của cấu trúc thực sự là một con trỏ tới cấu trúc chứa đầy các con trỏ hàm và mỗi con trỏ hàm đó phải lấy Foolàm đối số đầu tiên. Sau đó, Dispatch trở thành vấn đề tra cứu hàm và gọi nó bằng cách viết lại đối số đúng, điều này không khó thực hiện với macro và một chút xảo quyệt. (Bảng chức năng đó là cốt lõi của một lớp thực sự là ngôn ngữ như C ++.)

Hơn nữa, điều đó cũng mang lại cho bạn sự ràng buộc muộn: tất cả các mã công văn đều biết rằng nó đang gọi một phần bù cụ thể vào một bảng được chỉ ra bởi đối tượng. Điều đó chỉ cần được thiết lập trong quá trình phân bổ và khởi tạo đối tượng. Có thể đi với các chương trình điều phối thậm chí phức tạp hơn, mua cho bạn tính năng động hơn trong thời gian chạy (với chi phí tốc độ) nhưng chúng là những quả anh đào trên cơ chế cơ bản.

Tuy nhiên, điều đó không có nghĩa là C là ngôn ngữ OO. Điều quan trọng là C để bạn thực hiện tất cả các công việc khó khăn khi tự viết các quy ước và cơ chế điều phối (hoặc sử dụng thư viện của bên thứ ba). Đó là rất nhiều công việc. Nó cũng không cung cấp hỗ trợ cú pháp hoặc ngữ nghĩa, do đó, việc thực hiện một hệ thống lớp đầy đủ (với những thứ như thừa kế) sẽ gây đau đớn không cần thiết; nếu bạn đang xử lý một vấn đề phức tạp được mô tả tốt bởi mô hình OO, ngôn ngữ OO sẽ rất hữu ích trong việc viết giải pháp. Sự phức tạp thêm có thể được biện minh.


0

Tôi nghĩ rằng C là hoàn toàn tốt và phù hợp để thực hiện các khái niệm hướng đối tượng, nhún vai . Hầu hết sự khác biệt mà tôi thấy nó giữa tập hợp mẫu số chung của các ngôn ngữ được coi là hướng đối tượng là bản chất nhỏ và cú pháp theo quan điểm thực dụng của tôi.

Hãy bắt đầu với, giả sử, ẩn thông tin. Trong C, chúng ta có thể đạt được điều đó bằng cách đơn giản là ẩn định nghĩa của cấu trúc và làm việc với nó thông qua các con trỏ mờ. Điều đó mô hình hiệu quả publicso với privatesự khác biệt của các trường dữ liệu như chúng ta nhận được với các lớp. Và nó đủ dễ để làm và hầu như không chống thành ngữ, vì thư viện C tiêu chuẩn phụ thuộc rất nhiều vào việc này để đạt được việc che giấu thông tin.

Tất nhiên, bạn mất khả năng dễ dàng kiểm soát chính xác nơi cấu trúc được phân bổ trong bộ nhớ bằng cách sử dụng các loại mờ, nhưng đó chỉ là một sự khác biệt đáng chú ý giữa, giả sử, C và C ++. C ++ chắc chắn là một công cụ ưu việt khi so sánh khả năng lập trình các khái niệm hướng đối tượng của nó qua C trong khi vẫn duy trì quyền kiểm soát các bố cục bộ nhớ, nhưng điều đó không nhất thiết có nghĩa là Java hay C # vượt trội hơn C về mặt đó, vì hai điều đó làm cho bạn mất hoàn toàn khả năng kiểm soát nơi các đối tượng được phân bổ trong bộ nhớ.

Và chúng ta phải sử dụng một cú pháp fopen(file, ...); fclose(file);trái ngược với file.open(...); file.close();nhưng rất lớn. Ai quan tâm chứ? Có lẽ chỉ cần một người nào đó dựa nhiều vào việc tự động hoàn thành trong IDE của họ. Tôi thừa nhận rằng đó có thể là một tính năng rất hữu ích từ quan điểm thực tế, nhưng có lẽ không phải là một tính năng cần thiết cho một cuộc thảo luận về việc liệu một ngôn ngữ có phù hợp với OOP hay không.

Chúng tôi thiếu khả năng thực hiện hiệu quả protectedcác lĩnh vực. Tôi sẽ hoàn toàn nộp ở đó. Nhưng tôi không nghĩ có một quy tắc cụ thể có nội dung: " Tất cả các ngôn ngữ OO nên có một tính năng cho phép các lớp con truy cập các thành viên của lớp cơ sở mà các máy khách bình thường vẫn không thể truy cập được ." Bên cạnh đó, tôi hiếm khi thấy các trường hợp sử dụng cho các thành viên được bảo vệ mà ít nhất một chút nghi ngờ về việc trở thành một rào cản bảo trì.

Và tất nhiên chúng ta phải "bắt chước" OO đa hình với các bảng của con trỏ hàm và gợi ý cho họ cho văn năng động với một chút soạn sẵn hơn để khởi tạo những analogical vtablesvptrs, nhưng một chút soạn sẵn không bao giờ gây cho tôi nhiều nỗi đau.

Kế thừa là cách tương tự. Chúng ta có thể dễ dàng mô hình hóa điều đó thông qua thành phần, và tại các hoạt động bên trong của trình biên dịch, nó thực hiện cùng một điều. Tất nhiên, chúng tôi mất an toàn loại nếu chúng tôi muốn downcast , và tôi sẽ nói nếu bạn muốn hạ thấp tất cả, xin vui lòng không sử dụng C cho nó bởi vì những điều mọi người làm trong C để giả lập downcasting có thể là khủng khiếp từ một loại quan điểm an toàn, nhưng tôi thà người ta không nhìn xuống cả. Loại an toàn là thứ bạn có thể dễ dàng bắt đầu bỏ lỡ trong C vì trình biên dịch cung cấp rất nhiều thời gian để diễn giải mọi thứ chỉ là bit và byte, hy sinh khả năng bắt lỗi trong thời gian biên dịch, nhưng một số ngôn ngữ được coi là aren hướng đối tượng thậm chí còn gõ tĩnh.

Vì vậy, dunno, tôi nghĩ rằng nó ổn. Tất nhiên, tôi sẽ không sử dụng C để cố gắng tạo ra một cơ sở mã quy mô lớn tuân thủ các nguyên tắc RẮN, nhưng điều đó không nhất thiết là do sự xuất hiện ngắn của nó ở mặt trước hướng đối tượng. Rất nhiều tính năng tôi sẽ bỏ lỡ nếu tôi cố sử dụng C cho mục đích như vậy sẽ liên quan đến các tính năng ngôn ngữ không được coi là điều kiện tiên quyết cho OOP như an toàn loại mạnh, các hàm hủy được tự động gọi khi các đối tượng vượt quá phạm vi, toán tử quá tải, mẫu / generic và xử lý ngoại lệ. Đó là khi tôi thiếu các tính năng phụ trợ mà tôi đạt được cho C ++.


1
Tôi không chắc làm thế nào các nhà xây dựng không thể được coi là điều kiện tiên quyết cho OOP. Một phần của bản chất cơ bản của đóng gói là khả năng đảm bảo bất biến cho một đối tượng. Và điều đó đòi hỏi phải có khả năng khởi tạo đúng đối tượng trong những bất biến đó. Điều đó đòi hỏi một hàm tạo: một hoặc nhiều hàm, sao cho bạn không thể nói rằng đối tượng tồn tại cho đến khi ít nhất một trong số chúng được gọi.
Nicol Bolas

Khi chúng ta có thông tin ẩn với các kiểu mờ đục thì cách duy nhất để khởi tạo chúng và sao chép / sao chép và hủy chúng là thông qua các hàm tương đương tương tự như các hàm tạo và hàm hủy với khả năng duy trì các bất biến đó. Nó chỉ không theo mô hình trực tiếp vào ngôn ngữ và có thể giống với hình thức foo_createfoo_destroyfoo_clone, ví dụ:

Tất cả những gì chúng ta cần để duy trì bất biến struct Footrong trường hợp như vậy là đảm bảo các thành viên dữ liệu của nó không thể được truy cập và biến đổi bởi thế giới bên ngoài, loại mà mờ (được khai báo nhưng không được xác định với thế giới bên ngoài) ngay lập tức. Nó được cho là một hình thức che giấu thông tin mạnh mẽ hơn, ngang bằng với pimplC ++.

Vâng, tôi biết cách mọi người thực hiện OOP trong C, cảm ơn bạn. Quan điểm của tôi là tuyên bố của bạn rằng các nhà xây dựng "không được coi trực tiếp là điều kiện tiên quyết cho OOP" là do lỗi.
Nicol Bolas

Tôi hiểu rồi, tôi sẽ sửa nó ... nhưng trong trường hợp đó chúng ta có thể nói rằng C có cung cấp (đầy đủ không?) Cho các hàm hủy và hàm tạo không?

-1

Một câu hỏi không tồi.

Nếu bạn định gọi c là ngôn ngữ OO, bạn cũng sẽ cần gọi tất cả các ngôn ngữ thủ tục OO. Vì vậy, nó sẽ làm cho thuật ngữ vô nghĩa. c không có hỗ trợ ngôn ngữ cho OO. Nếu có cấu trúc, nhưng cấu trúc typeskhông có lớp.

Trên thực tế c không có nhiều tính năng so với hầu hết các ngôn ngữ. Nó chủ yếu được sử dụng cho tốc độ, sự đơn giản, phổ biến và hỗ trợ bao gồm cả tấn thư viện.

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.