2010-02-28 36 views
11

Bạn có thể đề xuất cú pháp cho ngôn ngữ C để sử dụng ngôn ngữ đó theo cách tương tự với ngôn ngữ hướng đối tượng không? Tôi biết rằng họ không thể giống nhau và một số từ khóa không có trong C, nhưng tôi tự hỏi liệu có cách nào tận dụng lợi thế của các khía cạnh nhất định (như thừa kế) ngay cả trong chương trình C hay không.C làm ngôn ngữ hướng đối tượng

+1

các bản sao chính xác http://stackoverflow.com/questions/2181079/object-oriented-programming-in-c/2181142#2181142 http://stackoverflow.com/questions/351733/can-you-write-object- direction-code-in-c –

+0

Xin lỗi tôi không thấy những câu hỏi đó. Nếu bạn muốn, bạn có thể đóng bài đăng này. –

+0

tôi không thể đóng nó, nhưng tôi sẽ đề nghị bạn google 'site: stackoverflow.com question-keywords' trước khi đặt câu hỏi :) –

Trả lời

10

Bạn có thể triển khai đa hình với chức năng thông thường và bảng ảo (vtables). Đây là một hệ thống khá gọn gàng mà tôi đã phát minh (dựa trên C++) cho một bài tập lập trình: alt text

Các nhà xây dựng cấp phát bộ nhớ và sau đó gọi hàm init của lớp nơi khởi tạo bộ nhớ. Mỗi hàm init cũng nên chứa một cấu trúc vtable tĩnh có chứa các con trỏ hàm ảo (NULL cho thuần ảo). Các hàm init của lớp bắt nguồn gọi hàm init của siêu lớp trước khi thực hiện bất cứ điều gì khác. Một API rất đẹp có thể được tạo bằng cách thực hiện các hàm bao hàm ảo (không bị nhầm lẫn với các hàm được chỉ ra bởi vtables) như sau (thêm static inline ở phía trước nó, nếu bạn làm điều này trong tiêu đề):

int playerGuess(Player* this) { return this->vtable->guess(this); } 

Độc thừa kế có thể được thực hiện bằng cách lạm dụng cách bố trí nhị phân của một cấu trúc: alt text

ý rằng đa kế thừa là Messier như sau đó bạn thường cần phải điều chỉnh giá trị con trỏ khi đúc giữa các loại thuộc hàng giáo phẩm.

Các loại dữ liệu cụ thể khác cũng có thể được thêm vào các bảng ảo. Ví dụ bao gồm thông tin loại thời gian chạy (ví dụ: nhập tên dưới dạng chuỗi), liên kết với vtable siêu lớp và chuỗi hủy. Bạn có thể muốn destructors ảo, nơi destructor lớp có nguồn gốc demotes đối tượng để siêu lớp của nó và sau đó đệ quy gọi destructor đó và như vậy, cho đến khi destructor lớp cơ sở đạt và cuối cùng giải phóng các struct.

+1

+1 đồ họa rất đẹp. Bây giờ tôi phải yêu thích câu hỏi này. Xem bạn đã làm gì? – wheaties

+0

chính xác sao chép http://stackoverflow.com/questions/2181079/object-oriented-programming-in-c/2181142#2181142 –

+0

Tôi đã thực hiện một số điều chỉnh nhỏ để phù hợp hơn với câu hỏi này, nhưng có - đó là một bản sao & dán :) – Tronic

2

Có là GObject library:

Hệ thống Object GLib, hoặc GObject, là một thư viện phần mềm miễn phí (bao phủ bởi LGPL) mà cung cấp một hệ thống đối tượng di động và minh bạch khả năng tương tác giữa các ngôn ngữ. GObject được thiết kế để sử dụng trực tiếp trong các chương trình C và thông qua các ràng buộc với các ngôn ngữ khác.

+1

+1 để không phát minh lại bánh xe –

+1

-1 vì không để ai đó học làm những việc – Nisanio

2

Giải pháp truyền thống là cấu trúc con trỏ hàm. Tôi nhấn mạnh truyền thống. Tôi có thể nói cho bạn biết loại mã tôi đã viết trong PL/I và C năm trước, nhưng tôi không tuyên bố nói về trạng thái của 'nghệ thuật' nếu bạn có thể gọi nghệ thuật này.

Có nhiều biến thể về điều này và dưới đây là một chút thỏa hiệp.

struct SortOfAnAbstractClass { 
    int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3); 
    void (*function2)(SortOfAnAbstractClass* this, char *arg); 
}; 

struct SortOfDerived { 
    struct SortOfAnAbstractClass base; 
    int instanceVariable1; 
}; 

SortOfAnAbstractClass getMeOne() { 
    SortOfDerived *d = malloc(sizeof SortOfDerived); 
    memset(d, 0, sizeof SortOfDerived); 
    d->function1 = myf1; 
    d->function2 = myf2; 
    return &d->base; 
}; 

và sau đó 'myf1' và 'myf2' truyền tham số 'này' của chúng và đi đến thị trấn. Bạn có thể mở rộng này để trông giống như một công văn ảo đầy đủ hơn.

Một biến thể phổ biến từ sương mù của thời gian:

struct SortOfAClass { 
    void *creatorInfo; 
    int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3); 
    void (*function2)(SortOfAnAbstractClass* this, char *arg); 
}; 

Trong sự thay đổi này, không có thừa kế bởi thu nhận. Các lớp dẫn xuất từng đưa trạng thái riêng của chúng vào đối tượng riêng của chúng trong creatorInfo.

+0

... Tôi không thấy 'struct SortOfAnAbstractBase' được định nghĩa ở bất kỳ đâu. Nó không thể là 'struct SortOfAnAbstractClass' vì bạn không muốn đặt một bảng con trỏ ảo trong mỗi cá thể đối tượng. –

0

Có nhiều biến thể để thực hiện lập trình OO trong C. Cách tôi muốn làm là định nghĩa một lớp cho mỗi tệp tiêu đề. Bạn sẽ thấy một hàm tạo new_testclass() mà chỉ khởi tạo các con trỏ hàm của bạn và trả về một con trỏ tới một lớp/cấu trúc được phân bổ. Ngoài ra bất kỳ hàm nào cũng đưa con trỏ đến lớp trong tham số đầu tiên (một cái gì đó C++ làm, nhưng ẩn).

testclass.h

#ifndef MALLOC_H 
    #include<malloc.h> 
#endif 
struct _testclass 
{ 
    int a; 
    int b; 
    int (*sum)(struct _testclass *obj); 
}; 

typedef struct _testclass testclass; 

int f_sum (testclass *obj) 
{ 
    return obj->a + obj->b; 
} 

testclass* new_testclass() 
{ 
    testclass *temp; 
    temp = (testclass*)malloc(sizeof(testclass)); 
    temp->sum = &f_sum; 
    return temp; 
} 

Sau đó, bạn chỉ có thể sử dụng nó.

testclass.c

#include <stdio.h> 
#include "testclass.h" 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int result; 
    testclass *testclass1; 
    testclass1 = new_testclass(); 
    testclass1->a = 5; 
    testclass1->b = 8; 
    result = testclass1->sum(testclass1); 
    printf("%d\n",result); 
    free(testclass1); 
    return 0; 
} 

Tất nhiên có một số khía cạnh quan trọng của lập trình hướng đối tượng mất tích ở đây, nhưng điều này cung cấp một phương pháp đơn giản cho trừu tượng cơ bản. Tôi tưởng tượng sự thừa kế sẽ yêu cầu một số loại mẹo tiền xử lý funky nếu nó có thể được thực hiện ở tất cả.

Các vấn đề liên quan