2009-03-23 32 views
19

Khi tôi được trình bày với các vấn đề lập trình, tôi tự nhiên bắt đầu chia chúng thành các đối tượng logic trong đầu của tôi. Ai có trách nhiệm gì, ai sở hữu cái gì, ai xuất phát từ cái gì, v.v.Đấu tranh với C đến từ vùng hướng đối tượng?

Tôi đang vật lộn với C. Tôi chỉ không biết làm thế nào để làm mọi thứ bằng ngôn ngữ thủ tục.

Nhà lập trình C có kinh nghiệm có thể giúp giải thích cách tôi nên suy nghĩ về các chương trình của mình trong thời gian thiết kế không?

Ví dụ: tôi muốn viết lớp Semaphore của riêng mình. Tôi sẽ tự nhiên cần một cấu trúc dữ liệu Queue cho chương trình của tôi, mà tôi cũng muốn viết bản thân mình. Nếu tôi cần phải làm điều này trong Java hoặc C#, tôi có thể chỉ đơn giản là whip lên một lớp Queue nhanh chóng và tạo ra một thể hiện mới của nó trong lớp Semaphore của tôi.

Nhưng trong C, không có đối tượng. Vì vậy, tôi phải nội tuyến tất cả các hành vi của cấu trúc dữ liệu hàng đợi của tôi?

Ai đó có thể giúp tôi "tải xuống" không?

liên quan: what is the best way to plan and organize development of an application in c

Trả lời

30

Nhưng trong C, không có đối tượng. Vì vậy, làm Tôi phải nội tuyến tất cả các hành vi của cấu trúc dữ liệu Hàng đợi của tôi?

số

Làm điều này.

  1. Xác định lớp học của bạn tuy nhiên bạn cảm thấy thoải mái khi thiết kế OO.

  2. Viết các thuộc tính của lớp của bạn dưới dạng cấu trúc ngôn ngữ C.

  3. Đặt cấu trúc đó trong tệp tiêu đề, cùng với tất cả các hàm hoạt động trên cấu trúc đó. Đảm bảo rằng MyStruct * self là đối số đầu tiên cho tất cả các "hàm chức năng" này.

  4. Viết mô-đun C với tất cả nội dung của hàm phương thức.

OO của người nghèo trong C. Nó hoạt động tốt. Chỉ cần được xử lý kỷ luật về việc đưa mọi thứ vào cấu trúc mà bạn cần - các biến cá thể công cộng và riêng tư - mọi thứ.

Nói chung, tránh cố gắng có các biến riêng tư ngay từ đầu.Bạn không có toàn bộ sức mạnh của trình biên dịch OO, vì vậy đừng bận tâm với các tính năng giá trị thấp như "riêng tư" hoặc "được bảo vệ".

+0

gạch dưới hàng đầu được đặt trước và không nên sử dụng. –

+1

Tùy thuộc vào cách api của bạn được xác định, bạn cũng có thể sử dụng các biến thể trên PIMPL để xác định biến riêng tư hoặc truyền tới/từ "char reserved [SOME_SIZE]" để người dùng không bao giờ thấy biến riêng tư là gì. Các tên @ –

+1

@evan có dấu gạch dưới hàng đầu chỉ được đặt trước phạm vi toàn cầu, không dành cho các thành viên struct –

15

Bạn vẫn có thể nghĩ đến hướng đối tượng với C.

Bạn chỉ cần để tạo ra một cấu trúc và một bộ các chức năng mà phải mất một con trỏ đến một thể hiện của struct đó làm tham số đầu tiên.

Đối với đa hình, bạn có thể chuyển kích thước của cấu trúc làm thành viên đầu tiên của cấu trúc, vì vậy bạn biết cách truyền nó.

Có một số lớn pdf of object oriented programming with ANSI-C here.

17

tôi sẽ sửa đổi câu trả lời S. Lott để sử dụng một opaque pointer để thực hiện dữ liệu ẩn của các thành viên của struct:

  1. Xác định lớp học của bạn tuy nhiên bạn muốn sử dụng thiết kế OO bình thường.
  2. Biến thành viên của lớp học của bạn đi vào cấu trúc ngôn ngữ C.
  3. Trong tệp tiêu đề, bạn không muốn để lộ các biến thành viên của đối tượng của bạn (vì các biến này sẽ là "riêng tư" trong ngôn ngữ OO). Thay vào đó, hãy sử dụng con trỏ mờ, tức là
    typedef struct mystruct_s *mystruct_t; // first argument to all your methods
  4. Đối với tất cả các phương pháp bạn muốn "công khai", hãy đặt chữ ký của họ vào tệp .h của bạn. Các thể thức phương thức nên đi vào tệp .c và các phương thức "riêng tư" chỉ được xác định trong tệp .c và cũng được khai báo tĩnh để ký hiệu của chúng không va chạm với các ký hiệu được xác định trong các tệp khác.

Quy ước đặt tên thông minh như dấu gạch dưới là không cần thiết khi sử dụng phương pháp này, nhưng điều đó có nghĩa là tất cả các biến thành viên của bạn sẽ là riêng tư. Chức năng có thể được công khai hay tư nhân, mặc dù chức năng công chúng là một phần của một không gian tên toàn cầu, do đó bạn có thể muốn để đủ điều kiện tên của họ với một tên "gói" như mystruct_push(), mystruct_pop() vv

Bạn cũng cần phải làm cho nó rõ ràng nếu người gọi hoặc thư viện chịu trách nhiệm gọi malloc()free(). Nhiều khả năng bạn sẽ có các phương thức mystruct_t *create()void destroy(mystruct_t *target).

+0

Tôi đồng ý; Tôi đã bỏ phiếu cho câu trả lời của S. Lott, nhưng chuyển phiếu bầu của tôi đến đây bởi vì ẩn nội dung của cấu trúc là cách tốt nhất để đi - tôi đã thực hiện chính xác điều này nhiều lần và nó hoạt động * thực sự * tốt. –

0

Tôi thứ hai là đề xuất để thực hiện "OO của người nghèo trong C." Tôi cũng nghĩ bạn có thể hưởng lợi từ việc dành thời gian để xem cách OO của Perl hoạt động. Về cơ bản, OO được thực hiện trong Perl bằng cách có trình thông dịch cung cấp mọi phương thức với cá thể như một tham số đầu tiên ngầm định. Bạn sẽ muốn làm tương tự trong C, rõ ràng, và sử dụng thực sự, tổ chức mã thực sự tốt kể từ khi trình biên dịch sẽ không thực thi đóng gói tốt cho bạn.

Nhân tiện, bạn có thể thực thi việc giữ các thành viên của cấu trúc của mình ở chế độ riêng tư bằng cách sử dụng opaque pointers. Tôi dường như nhớ lại rằng các tiêu chuẩn và đề xuất lập trình GNU bao gồm một kỹ thuật để làm điều này bằng cách cơ bản đúc mọi thứ để làm mất hiệu lực * khi nó được truyền đi, sau đó sử dụng typedefs để đặt tên cho từng loại con trỏ mờ đục cụ thể. (ví dụ: mỗi "lớp")

2

Kiểm tra Lua C api. Nó đã được ánh sáng hướng dẫn của tôi như xa như thiết kế giao diện C đi. Mỗi hàm nhận trạng thái Lua như một đối số hàng đầu để trở thành "cái này" của bạn. Thừa kế là một chút phức tạp hơn nhưng Chipmunk quản lý để làm một công việc khá tốt phơi bày các chức năng mà có một cấu trúc hình dạng chung và làm việc ra các chi tiết của chức năng mà thực sự được gọi là thông qua một "klass". Bạn thường có thể khai thác void * để có các hàm có các kiểu khác nhau (cấu trúc) theo cách bạn sẽ quá tải trong OO. Nó có thể cảm thấy một chút hackish ở lần nhưng hoạt động tốt.

4

Tôi đã có một khoảng thời gian chuyển từ tư duy thủ tục sang tư duy OO, vì vậy tôi cảm thấy nỗi đau của bạn.

Tôi thấy rằng để tìm hiểu cách tạo đối tượng, tốt nhất là hãy nghĩ về cách chúng sẽ hiển thị với người gọi. Cách tiếp cận tương tự có thể giúp bạn, đi theo cách khác. Hãy xem xét những gì API cho thành phần của bạn sẽ như thế nào. Một cách tốt là nghiên cứu các API C hiện có (tôi đã sử dụng các API Java chuẩn như một tập hợp các ví dụ về một API OO).

Bạn đang sử dụng để sử dụng một cái gì đó thành phần hàng đợi như thế này:

import some.package.Queue; 

Queue q = new Queue(); 
q.add(item); 

Trong một C api điển hình, bạn mong muốn một cái gì đó giống như:

#include <queue.h> // provides queue, make_queue(), queue_add(), others 

queue q = make_queue(); // queue is probably a struct, or a struct* 
queue_add(q,item); 

Bất cứ khi nào bạn thấy mình suy nghĩ trong các đối tượng, tạo ra một biến đổi tương tự.

Bạn có thể sử dụng con trỏ cho các chức năng và tương tự, để tạo cấu trúc giống như đối tượng trong C - nhưng hàng nghìn lập trình viên C đã quản lý mà không cần.

Chúc may mắn!

1

Nguyên C++ chỉ là một trình biên dịch mà viết code C từ các nguồn C++; sau đó, tất cả các phương thức OOP đều có sẵn trong C - nó chỉ là trình biên dịch sẽ không giúp bạn, và không cung cấp tất cả các khả năng biên dịch-thời gian chẳng hạn như mẫu, ghi đè toán tử, ẩn dữ liệu, v.v.

  1. C++ "struct" (có thể vẫn là) tương đương với "lớp" với tất cả thành viên "công khai".
  2. Chức năng của thành viên có thể được triển khai dưới dạng con trỏ hàm trong cấu trúc; điều này có thể cung cấp sự đóng gói và đa hình. Các nhà xây dựng tồn tại trong phạm vi toàn cầu trừ khi bạn đang sử dụng các nhà máy. Các cấu trúc có thể là các hàm thành viên.
  3. Sử dụng các chức năng của thành viên truy cập, như getColor(), setColor() có thể làm giảm sự khác biệt nội bộ và cung cấp một số dữ liệu ẩn. Nếu bạn thực sự muốn, bạn có thể sử dụng đề xuất ẩn của Brian Bondy với các macro.
  4. Thực tế, có rất nhiều phần mềm nguồn mở thư viện cung cấp container tiêu chuẩn - bảng băm, mảng năng động, danh sách liên kết, vv
Các vấn đề liên quan