Czy istnieje sposób pisania kodu podobnego do OO w języku programowania C
?Jak mogę symulować polimorfizm w stylu OO w C?
Zobacz także:
znaleźć, szukając na "[c] oo".
Czy istnieje sposób pisania kodu podobnego do OO w języku programowania C
?Jak mogę symulować polimorfizm w stylu OO w C?
Zobacz także:
znaleźć, szukając na "[c] oo".
Pierwszy kompilator C++ („C z klasami”) faktycznie wygenerować kod w C, więc to na pewno wykonalne.
Zasadniczo twoją klasą podstawową jest struct; pochodne struktury muszą zawierać podstawową strukturę na pierwszej pozycji, tak aby wskaźnik do "pochodnej" struktury również był prawidłowym wskaźnikiem do podstawowej struktury.
typedef struct {
data member_x;
} base;
typedef struct {
struct base;
data member_y;
} derived;
void function_on_base(struct base * a); // here I can pass both pointers to derived and to base
void function_on_derived(struct derived * b); // here I must pass a pointer to the derived class
Funkcje te mogą być częścią struktury jako wskaźników funkcji, tak, że składnia jak p> Rozmowy (P) staje się możliwe, ale trzeba jeszcze wyraźnie przekazać wskaźnik do struktury do samej funkcji .
Nie wyjaśnia to, w jaki sposób nadpisanie metody działałoby w C. Jak można przesłonić function_on_base, aby uzyskać dostęp do pochodnego memeber_y, jak to możliwe w wywołaniach polimorficznych C++? –
Nadpisywanie nie jest możliwe w C. –
Ta odpowiedź jest niepoprawna. Przekazywanie 'wyprowadzonej struktury *' do 'function_on_base' nie będzie się kompilować; 'wyprowadzenie struct *' jest innym typem niż 'struct base *' nawet jeśli adres jest poprawny; jednak jeśli rzucisz wskaźnik z "wyprowadzonego *" na "podstawowy *", to zadziała (ale stracisz kontrolę nad kompilacją, a zamiast tego dostaniesz awarię w środowisku wykonawczym). @PatrickCollins Przesłanianie _jest_ możliwe w C: http://pastebin.com/W5xEytbv – weberc2
Powszechnym podejściem jest zdefiniowanie struktury ze wskaźnikami do funkcji. To definiuje "metody", które można wywoływać w dowolnym typie. Podtypy następnie ustawiają własne funkcje w tej wspólnej strukturze i zwracają je.
Na przykład w jądra linux, istnieje struct:
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
struct dentry * (*lookup) (struct inode *,struct dentry *,
struct nameidata *);
...
};
Każdy zarejestrowany typ systemu plików, a następnie rejestruje swoje funkcje create
, lookup
, a pozostałe funkcje. Reszta kodu można użyć inode_operations niż ogólna:
struct inode_operations *i_op;
i_op -> create(...);
Zasadniczo to w jaki sposób cfront (oryginalny kompilator C++) przekonwertował C++ na C, który został skompilowany przy pomocy PCC. Wiele się dowiedziałem, jak to działało, radząc sobie z plikami bazowymi z tego bałaganu. –
Brzmi jak zabawa :-) –
C++ nie jest tak daleko od C
Klasy są konstrukcje z ukrytą wskaźnik do tablicy wskaźników funkcji zwanej vtable. Sam Vtable jest statyczny. Kiedy typy wskazują na Vtables o tej samej strukturze, ale tam, gdzie wskaźniki wskazują na inną implementację, pojawia się polimorfizm.
Zaleca się enkapsulację logiki połączeń w funkcji, która przyjmuje parametr struct jako, aby uniknąć bałaganu w kodzie.
Powinieneś także encapsulcte struktur instancjonowanie i inicjalizacji w funkcjach (to jest równoważne z konstruktorem C++) i usuwanie (destruktor w C++). W każdym razie są to dobre praktyki.
typedef struct
{
int (*SomeFunction)(TheClass* this, int i);
void (*OtherFunction)(TheClass* this, char* c);
} VTable;
typedef struct
{
VTable* pVTable;
int member;
} TheClass;
Aby wywołać metodę:
int CallSomeFunction(TheClass* this, int i)
{
(this->pVTable->SomeFunction)(this, i);
}
Funkcje plików fopen, fclose, fread są przykładami kodu oo in C zamiast prywatnych danych w klasie, pracują na strukturze pliku, który służy do enkapsulacji danych, a funkcje języka C działają jako funkcje klasy elementu. http://www.amazon.com/File-Structures-Object-Oriented-Approach-C/dp/0201874016
Tytuł brzmi teraz: "Podejście obiektowe z C++" – prinzdezibel
Wskazana książka to tylko C++. Uwaga: mam kopię i nie polecam jej dzisiaj. Gdybym miał jedno zalecenie OO w C, aby dać dzisiaj, byłoby to interfejsy C i implementacje: Techniki tworzenia oprogramowania wielokrotnego użytku David Hanson (http://amzn.com/0201498413). Absolutnie genialna książka i większość programistów dobrze by to zrozumiała, większość przykładów pochodzi z kompilatorów, więc kod jest wzorowy. – Harry
Dodatek B wyrobu Open Reusable Object Models, Ian Piumarta Alessandro Warth z VPRI stanowi wykonanie modelu obiektu gnu C, około 140 linii kodu. To fascynująca lektura!
Oto niebuforowanych wersja makra, który wysyła wiadomości do obiektów, używając rozszerzenia GNU na C (oświadczenie ekspresji):
struct object;
typedef struct object *oop;
typedef oop *(*method_t)(oop receiver, ...);
//...
#define send(RCV, MSG, ARGS...) ({ \
oop r = (oop)(RCV); \
method_t method = _bind(r, (MSG)); \
method(r, ##ARGS); \
})
W tym samym dokumencie, zajrzyj na object
, vtable
, vtable_delegated
i symbol
, funkcje i funkcje _bind
i vtable_lookup
.
Pozdrawiam!
Spojrzałem na wszystkich elses' odpowiedzi i podszedł z tym:
#include <stdio.h>
typedef struct
{
int (*get)(void* this);
void (*set)(void* this, int i);
int member;
} TheClass;
int Get(void* this)
{
TheClass* This = (TheClass*)this;
return This->member;
}
void Set(void* this, int i)
{
TheClass* This = (TheClass*)this;
This->member = i;
}
void init(TheClass* this)
{
this->get = &Get;
this->set = &Set;
}
int main(int argc, char **argv)
{
TheClass name;
init(&name);
(name.set)(&name, 10);
printf("%d\n", (name.get)(&name));
return 0;
}
Mam nadzieję, że odpowiedzi na kilka pytań.
Dobry przykład. Byłoby jeszcze lepiej, gdybyś miał 2 "pochodne" klasy z różnymi init/get/set. "prywatni" członkowie/funkcje mogą być wykonywane za pomocą [opaque structs] (http://stackoverflow.com/questions/3965279/opaque-c-structs-how-should-they-be-declared). Konwencja nazewnictwa jest również ważna: 'mylib_someClass_aMethod (this)' jest dobrą opcją. –
To wygląda schludnie. Umieściłem to w pliku c i skompilowałem w porządku dla mikrokontrolera ARM. Nie docieram daleko, ale po prostu lubię upuszczać notatkę jako potwierdzenie do postu red_hax0r. – coarist
gdzie jest polimorfizm? –
Z Wikipedii: W języku programowania i teorii typów, polimorfizm (z greckiego πολύς, polys, "wiele, dużo" i μορφή, morphē, "forma, kształt") jest zapewnieniem pojedynczego interfejsu dla podmiotów różnych typy.
Powiedziałbym więc, że jedynym sposobem wdrożenia go w C jest użycie argumentów variadic wraz z niektórymi (semi) automatycznymi typami zarządzania informacjami. Na przykład w C++ można pisać (przepraszam za trivialness):
void add(int& result, int a1, int a2);
void add(float& result, float a1, float a2);
void add(double& result, double a1, double a2);
W C, między innymi rozwiązaniami, to najlepsze co możesz zrobić, to coś takiego:
int int_add(int a1, int a2);
float float_add(float a1, fload a2);
double double_add(double a1, double a2);
void add(int typeinfo, void* result, ...);
Następnie trzeba:
Jestem prawie pewien, że każda inna realizacja polimorfizmu powinien wyglądać podobnie jak ten sam jeden. Powyższe odpowiedzi wydają się raczej próbować adresować dziedziczenie bardziej niż polimorfizm!
W C11 nowe słowo kluczowe [_Generic] (http://en.cppreference.com/w/c/language/generic) upraszcza ten wzorzec projektowania. Gorąco polecam dla osób wybierających to podejście. –
#include <stdio.h>
typedef struct {
int x;
int z;
} base;
typedef struct {
base;
int y;
int x;
} derived;
void function_on_base(base * a) // here I can pass both pointers to derived and to base
{
printf("Class base [%d]\n",a->x);
printf("Class base [%d]\n",a->z);
}
void function_on_derived(derived * b) // here I must pass a pointer to the derived class
{
printf("Class derived [%d]\n",b->y);
printf("Class derived [%d]\n",b->x);
}
int main()
{
derived d;
base b;
printf("Teste de poliformismo\n");
b.x = 2;
d.y = 1;
b.z = 3;
d.x = 4;
function_on_base(&b);
function_on_base(&d);
function_on_derived(&b);
function_on_derived(&d);
return 0;
}
Wyjście było:
Class base [3]
Class base [1]
Class base [4]
Class derived [2]
Class derived [3]
Class derived [1]
Class derived [4]
tak to działa, jego kod polimorficzny.
UncleZeiv wyjaśnił o tym na samym początku.
Aby również zbudować funkcjonalność OO w C, można przejrzeć poprzednie odpowiedzi.
Ale, (jak zostało zadane w innych pytaniach przekierowanych na ten), jeśli chcesz zrozumieć, czym jest polimorfizm, na przykład w języku C.Może się mylę, ale nie mogę myśleć o niczym łatwym do zrozumienia, jak arytmetyczne wskaźniki C. Moim zdaniem, arytmetyka wskaźnika jest z natury polimorficzna w C. W poniższym przykładzie ta sama funkcja (metoda w OO), a mianowicie dodanie (+), spowoduje inne zachowanie w zależności od właściwości struktur wejściowych.
Przykład:
double a*;
char str*;
a=(double*)malloc(2*sizeof(double));
str=(char*)malloc(2*sizeof(char));
a=a+2; // make the pointer a, point 2*8 bytes ahead.
str=str+2; // make the pointer str, point 2*1 bytes ahead.
Disclaimer: Jestem bardzo nowa w C i bardzo cieszymy się być poprawione i uczyć się od Inni użytkownika, lub nawet całkowicie usunąć tę odpowiedź, powinno być źle. Wielkie dzięki,
dzięki za podpowiedź z nawiasami kwadratowymi. Tego nie wiedziałem. – prinzdezibel
Tak, to musi być bardziej odkrywalne czy coś. Próbowałem sformułować dobrą sugestię dla uservoice, ale jej nie łączę. – dmckee