Đọc SICP và tìm hiểu Đề án, và ý tưởng thực tế về các loại dữ liệu trừu tượng . Sau đó, mã hóa bằng C rất dễ dàng (vì với SICP, một chút C và một chút PHP, Ruby, v.v ... suy nghĩ của bạn sẽ được mở rộng đủ và bạn sẽ hiểu rằng lập trình hướng đối tượng có thể không phải là phong cách tốt nhất trong tất cả các trường hợp, nhưng chỉ cho một số loại chương trình). Hãy cẩn thận về phân bổ bộ nhớ động C , có lẽ là phần khó nhất. Các C99 hoặc C11 tiêu chuẩn ngôn ngữ lập trình và nó thư viện chuẩn C thực sự là khá nghèo (nó không biết về TCP hoặc thư mục!), Và bạn thường sẽ cần một số thư viện bên ngoài hoặc các giao diện (ví dụPOSIX , libcurl cho thư viện máy khách HTTP, libonion cho thư viện máy chủ HTTP, GMPlib cho các bignums, một số thư viện như libunistring cho UTF-8, v.v ...).
Các "đối tượng" của bạn thường ở C một số struct
-s liên quan và bạn xác định tập hợp các hàm hoạt động trên chúng. Đối với các hàm ngắn hoặc rất đơn giản, hãy xem xét việc xác định chúng, với các hàm có liên quan struct
, như static inline
trong một số tệp tiêu đề foo.h
sẽ là #include
-d ở nơi khác.
Lưu ý rằng lập trình hướng đối tượng không phải là mô hình lập trình duy nhất . Trong một số trường hợp, các mô hình khác đáng giá ( lập trình chức năng à Ocaml hoặc Haskell hoặc thậm chí Scheme hoặc Commmon Lisp, lập trình logic à la Prolog, v.v ... Đọc thêm blog của J.Pitrat về trí tuệ nhân tạo khai báo). Xem cuốn sách của Scott: Ngôn ngữ lập trình thực dụng
Trên thực tế, một lập trình viên ở C, hoặc trong Ocaml, thường không muốn viết mã theo kiểu lập trình hướng đối tượng. Không có lý do gì để ép bản thân nghĩ về đồ vật khi điều đó không hữu ích.
Bạn sẽ xác định một số struct
và các chức năng hoạt động trên chúng (thường thông qua con trỏ). Bạn có thể cần một số công đoàn được gắn thẻ (thường là, struct
với một thành viên thẻ, thường là một số enum
và một số union
bên trong) và bạn có thể thấy hữu ích khi có một thành viên mảng linh hoạt ở cuối một số struct
-s của bạn .
Nhìn vào bên trong mã nguồn của một số phần mềm miễn phí hiện có trong C (xem github & sourceforge
để tìm một số). Có lẽ, cài đặt và sử dụng bản phân phối Linux sẽ hữu ích: nó được tạo ra hầu như chỉ bằng phần mềm miễn phí, nó có trình biên dịch phần mềm C miễn phí tuyệt vời ( GCC , Clang / LLVM ) và các công cụ phát triển. Xem thêm Lập trình Linux nâng cao nếu bạn muốn phát triển cho Linux.
Đừng quên để biên dịch với tất cả các cảnh báo và thông tin gỡ lỗi, ví dụ như gcc -Wall -Wextra -g
-notably trong sự phát triển & gỡ lỗi phases- và học cách sử dụng một số công cụ, ví dụ như valgrind để săn rò rỉ bộ nhớ , các gdb
chương trình gỡ rối, vv Hãy chăm sóc để hiểu rõ những gì đang undefined hành vi và mạnh mẽ tránh nó (hãy nhớ rằng một chương trình có thể có một số UB và đôi khi dường như "hoạt động").
Khi bạn thực sự cần các cấu trúc hướng đối tượng (đặc biệt là kế thừa ), bạn có thể sử dụng các con trỏ tới các cấu trúc liên quan và các hàm. Bạn có thể có máy móc vtable của riêng mình , có mỗi "đối tượng" bắt đầu bằng một con trỏ tới một struct
con trỏ hàm chứa. Bạn tận dụng khả năng truyền một loại con trỏ sang một loại con trỏ khác (và thực tế là bạn có thể truyền từ một loại struct super_st
có chứa các loại trường giống như các loại bắt đầu struct sub_st
để mô phỏng thừa kế). Lưu ý rằng C là đủ để thực hiện các hệ thống đối tượng khá tinh vi - cụ thể bằng cách tuân theo một số quy ước -, như GObject (từ GTK / Gnome) chứng minh.
Khi bạn thực sự cần đóng , bạn sẽ thường mô phỏng chúng bằng các cuộc gọi lại , với quy ước rằng mọi chức năng sử dụng một cuộc gọi lại đều được truyền cả con trỏ hàm và một số dữ liệu máy khách (được con trỏ hàm sử dụng khi nó gọi). Bạn cũng có thể có (thông thường) các đóng cửa giống như của bạn struct
(chứa một số con trỏ hàm và các giá trị đóng).
Vì C là ngôn ngữ cấp độ rất thấp, điều quan trọng là phải xác định và ghi lại các quy ước của riêng bạn (lấy cảm hứng từ thực tiễn trong các chương trình C khác), đặc biệt là về quản lý bộ nhớ và có thể cả một số quy ước đặt tên. Nó rất hữu ích để có một số ý tưởng về kiến trúc tập lệnh . Đừng quên rằng một C trình biên dịch có thể làm được nhiều việc tối ưu trên mã của bạn (nếu bạn hỏi nó), do đó, không quan tâm quá nhiều về việc làm vi tối ưu bằng tay, nghỉ đó để trình biên dịch của bạn ( gcc -Wall -O2
cho biên soạn được tối ưu hóa của phát hành phần mềm). Nếu bạn quan tâm đến điểm chuẩn và hiệu suất thô, bạn nên kích hoạt tối ưu hóa (một khi chương trình của bạn đã được gỡ lỗi).
Đừng quên rằng đôi khi siêu lập trình là hữu ích . Rất thường xuyên, phần mềm lớn được viết bằng C chứa một số tập lệnh hoặc chương trình đặc biệt để tạo một số mã C được sử dụng ở nơi khác (và bạn cũng có thể chơi một số thủ thuật tiền xử lý C bẩn , ví dụ như X-macro ). Tồn tại một số trình tạo chương trình C hữu ích (ví dụ: yacc hoặc gnu bison để tạo trình phân tích cú pháp, gperf để tạo các hàm băm hoàn hảo, v.v ...). Trên một số hệ thống (đặc biệt là Linux & POSIX), bạn thậm chí có thể tạo một số mã C khi chạy trong generated-001.c
tệp, biên dịch nó thành một đối tượng chia sẻ bằng cách chạy một số lệnh (như gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so
) trong thời gian chạy, tải động đối tượng được chia sẻ đó bằng dlopen& nhận được một con trỏ hàm từ một tên bằng cách sử dụng dlsym . Tôi đang thực hiện các thủ thuật như vậy trong MELT (ngôn ngữ dành riêng cho miền giống Lisp có thể hữu ích cho bạn, vì nó cho phép tùy chỉnh trình biên dịch GCC ).
Lưu ý về các khái niệm và kỹ thuật thu gom rác ( đếm tham chiếu thường là một kỹ thuật để quản lý bộ nhớ trong C và IMHO là một dạng thu gom rác kém, không xử lý tốt các tham chiếu vòng tròn ; bạn có thể có các con trỏ yếu để giúp về điều đó, nhưng nó có thể là khó khăn). Đôi khi, bạn có thể cân nhắc sử dụng công cụ thu gom rác bảo thủ của Boehm .
qux = foo.bar(baz)
trở thànhqux = Foo_bar(foo, baz)
.