Dlaczego C nie jest uważany za język „obiektowy”?

92

Wydaje się, że C ma swoje quasi-obiekty, takie jak „struktury”, które można uznać za obiekty (w sposób, w jaki normalnie myślimy).

A także same pliki C są w zasadzie osobnymi „modułami”, prawda? Czy zatem moduły nie są też czymś w rodzaju „obiektów”? Jestem zdezorientowany, dlaczego C, który wydaje się tak podobny do C ++, jest uważany za język „proceduralny” niskiego poziomu, podczas gdy C ++ jest „obiektowym” wysokiego poziomu

* edycja: (wyjaśnienie) dlaczego i gdzie jest narysowana linia, czym jest „obiekt”, a czym nie jest?

Mroczny Templariusz
źródło
40
Wszystko - dlaczego głosowanie w dół? To podstawowe pytanie, ale nie złe.
Jon Hopkins,
7
Możesz efektywnie korzystać z zasad OO w C (i ludzie, którzy piszą dobry kod C zazwyczaj tak robią), ale język nie jest zbudowany wokół, aby ułatwić, podobnie jak wiele nowszych języków.
asveikau,
5
C ma po prostu inne, prostsze i (szczerze mówiąc) lepiej zdefiniowane (przynajmniej wśród społeczności Open Source) podejście do pozyskiwania danych. C ++ jest zwykle potęgą abstrakcji i pozwala na wiele wspaniałych rzeczy, ale wiąże się to z kosztem zrozumienia, jak [nie] właściwie z nich korzystać, czego często brakuje w popularnych programach. Zobacz moją pełną odpowiedź, aby uzyskać więcej informacji.
Yam Marcovic,
1
W skrócie: Struktury nie mogą mieć metod. (Wskaźnik do funkcji nie całkiem ją wycina).
SF.
1
Możliwe jest programowanie obiektowe w języku C, z pewnymi trudnościami. Ale to nie czyni tego obiektowym .
Wedge

Odpowiedzi:

101

Wydaje się, że C ma swoje quasi-obiekty, takie jak „struktury”, które można uznać za obiekty

Przyjrzyjmy się razem z tobą na stronie Wikipedii poświęconej programowaniu obiektowemu i sprawdźmy cechy struktur typu C, które odpowiadają temu, co tradycyjnie uważa się za styl obiektowy:

(OOP) to paradygmat programowania wykorzystujący „obiekty” - struktury danych składające się z pól danych i metod wraz z ich interakcjami

Czy struktury C składają się z pól i metod wraz z ich interakcjami ? Nie.

Techniki programowania mogą obejmować takie funkcje, jak abstrakcja danych, enkapsulacja, przesyłanie wiadomości, modułowość, polimorfizm i dziedziczenie.

Czy struktury C wykonują którąkolwiek z tych rzeczy w sposób „pierwszej klasy”? Nie. Język działa przeciwko tobie na każdym kroku.

podejście obiektowe zachęca programistę do umieszczania danych tam, gdzie nie są bezpośrednio dostępne dla reszty programu

Czy struktury C to robią? Nie.

Program zorientowany obiektowo zwykle zawiera różne typy obiektów, z których każdy odpowiada konkretnemu rodzajowi złożonych danych, którymi należy zarządzać, a może obiektowi lub koncepcji w świecie rzeczywistym

Czy struktury C to robią? Tak.

Obiekty można traktować jako zawijanie ich danych w zestawie funkcji zaprojektowanych w celu zapewnienia właściwego wykorzystania danych

Nie.

każdy obiekt może odbierać wiadomości, przetwarzać dane i wysyłać wiadomości do innych obiektów

Czy sama struktura może wysyłać i odbierać wiadomości? Nie. Czy może przetwarzać dane? Nie.

Struktury danych OOP mają tendencję do „noszenia ze sobą własnych operatorów”

Czy dzieje się tak w C? Nie.

Dynamiczna wysyłka ... Hermetyzacja ... Polimorfizm podtypu ... Dziedziczenie obiektu ... Otwarta rekurencja ... Klasy obiektów ... Instancje klas ... Metody, które działają na dołączone obiekty ... Przekazywanie wiadomości ... , Abstrakcja

Czy którakolwiek z tych cech struktur C? Nie.

Jak myślisz, które cechy struktur są „obiektowe”? Bo nie mogę znaleźć dowolny inny niż fakt, że kodowanym określenia rodzajów .

Teraz oczywiście możesz tworzyć struktury, które mają pola wskazujące funkcje. Możesz utworzyć struktury posiadające pola, które są wskaźnikami do tablic wskaźników funkcji, odpowiadającymi wirtualnym tabelom metod. I tak dalej. Oczywiście możesz emulować C ++ w C. Ale to jest bardzo nie idiomatyczny sposób programowania w C; lepiej byłoby po prostu używać C ++.

A także same pliki C są w zasadzie osobnymi „modułami”, prawda? Czy zatem moduły nie są też czymś w rodzaju „obiektów”?

Ponownie, jakie cechy modułów uważasz, że działają one jak obiekty? Czy moduły obsługują abstrakcję, enkapsulację, przesyłanie wiadomości, modułowość, polimorfizm i dziedziczenie?

Abstrakcja i enkapsulacja są dość słabe. Oczywiście moduły są modułowe; dlatego nazywane są modułami. Wiadomości? Tylko w tym sensie, że wywołanie metody jest komunikatem, a moduły mogą zawierać metody. Wielopostaciowość? Nie. Dziedzictwo? Nie. Moduły są dość słabymi kandydatami na „obiekty”.

Eric Lippert
źródło
15
Nie zgadzam się z tym, że „emulowanie C ++” (twój termin) nie jest idiomatyczne C. Jednym z liczników jest przykład, w jaki sposób jądro systemu operacyjnego zwykle wykonuje operacje na plikach - weźmy Linux za przykład, gdzie masz struktury pełne wskaźników funkcji. Mogą to być idiomy „specyficzne dla domeny” (powiedzmy ograniczone do pisania sterowników na * nix), ale są rozpoznawalne i wykonują zadanie wystarczająco dobrze dla niektórych celów. Istnieje również kilka przykładów bibliotek trybu użytkownika, które dość dobrze rozumieją pojęcie OO; weź Gtk + i biblioteki, od których zależy. Nazwij to hacky i możesz mieć rację, ale nie jest to okropne do pracy
asveikau 10.10.11
5
@asveikau: Czy pomysł, że praktyka jest niezwykła (nawet jeśli nie jest niespotykana) i „hacky”, oznacza, że ​​z definicji nie jest idiomatyczna?
Adam Robinson
19
@asveikau: Jasne, są rzeczy, które możesz zrobić, aby programy C były bardziej stylowe. Ale, jak mówisz, wymaga dyscypliny; same cechy języka nie prowadzą naturalnie do enkapsulacji, polimorfizmu, dziedziczenia klas i tak dalej. Deweloper może raczej narzucić ten wzór na język. Nie oznacza to, że struktury są logicznie tym samym co obiekty. Cholera, możesz także programować w stylu OO w Lisp, ale to nie znaczy, że komórki przeciwne są obiektami.
Eric Lippert,
3
@asveikau, czy mogę zasugerować, że twoja (błędna) interpretacja „idiomu” jako „własnego” jest delikatnie… idiosynkratyczna? :)
Benjol,
8
@BillK: Struktury nie mogą zawierać kodu w C. Struktury mogą zawierać wskaźniki funkcji , które są danymi . Wskaźniki funkcji nie są kodem . Kod jest artefaktem tekstowym stworzonym przez programistę.
Eric Lippert,
46

Kluczowe słowo to „zorientowane”, a nie „obiekt”. Nawet kod C ++, który używa obiektów, ale używa ich jak struktur, nie jest zorientowany obiektowo .

Zarówno C, jak i C ++ mogą wykonywać OOP (oprócz braku kontroli dostępu w C), ale składnia do robienia tego w C jest niewygodna (co najmniej), podczas gdy składnia w C ++ sprawia, że ​​jest bardzo zachęcająca. C jest zorientowany na procedury, podczas gdy C ++ jest zorientowany na obiekty, pomimo prawie identycznych podstawowych możliwości w tym zakresie.

Kod, który wykorzystuje obiekty do implementacji projektów, które można wykonać tylko z obiektami (zwykle oznacza wykorzystanie polimorfizmu) jest kodem obiektowym. Kod, który używa obiektów jako niewiele więcej niż worków danych, nawet używając dziedziczenia w języku zorientowanym obiektowo, jest tak naprawdę tylko kodem proceduralnym, który jest bardziej skomplikowany, niż powinien. Kod w C, który używa wskaźników funkcji, które są zmieniane w czasie wykonywania z strukturami pełnymi danych, jest rodzajem polimorfizmu i można powiedzieć, że jest „obiektowy”, nawet w języku zorientowanym proceduralnie.

Kylben
źródło
2
+1 Za wskazanie naszym C może być OO. Nie jest to wygodne, ale można to zrobić.
dietbuddha,
Łatwiej jest tworzyć obiekty w VBA, ale nie uważałbym też, że obiekt jest „zorientowany”.
JeffO
VBA nazywam „obiektowym”. Używa obiektów, ale nie polimorficznie, a przy odrobinie pracy, którą w nim wykonałem, nie jestem pewien, czy potrafisz nawet robić polimorfizm bez względu na to, jakiego rodzaju akrobatyki kodu próbujesz. Jest to w zasadzie język proceduralny z enkapsulacją.
kylben
2
Większość języków może działać jako OO, funkcjonalna lub prawie w każdym stylu. Różnica polega na „Oriented” i nigdy wcześniej nie słyszałem, żeby tak to wyglądało. Chciałbym móc głosować 3 razy i zaakceptować, to właściwa odpowiedź.
Bill K
1
@kylben Przechowywanie kodu SQL w tabeli nie byłoby zbyt dużym wysiłkiem, a następnie wyodrębnianie i wykonywanie (czyniąc tabelę obiektem). Byłby to interesujący eksperyment. Właściwie to trochę kuszące ...
Bill K
19

W oparciu o zasady najwyższego poziomu:

Obiekt jest enkapsulacją danych i zachowania w połączony ze sobą sposób, dzięki czemu działają one jako całość, które mogą być tworzone wielokrotnie i działały jako czarna skrzynka, jeśli znasz interfejs zewnętrzny.

Struktury zawierają dane, ale nie zachowują się, dlatego nie można ich uważać za obiekty.

Moduły zawierają zarówno zachowanie, jak i dane, ale nie są hermetyzowane w taki sposób, że oba są ze sobą powiązane i na pewno nie można ich wielokrotnie utworzyć.

I to zanim przejdziesz do dziedziczenia i polimorfizmu ...

Jon Hopkins
źródło
Dlaczego zachowanie i dane w modułach nie są powiązane? Czy funkcje członka nie są w zasadzie „zachowaniem” danych istniejących w module?
Dark Templar,
4
Problem polega na tym, że nie są zamknięte, a nie, że nie są powiązane.
Eoin Carroll
W rzeczywistości obiekty koncentrują się głównie wokół zachowania , a nie danych. Dane są / powinny być obywatelem drugiej kategorii w OOP. Zamiast tego struktury są skupione wokół danych i nie zachowują się.
Sklivvz
1
@Dark Templar - Co powiedział Eoin ... To jest charakter związku. Mogę zobaczyć, gdzie idziesz z - można oczywiście użyć strukturach wewnątrz modułu w taki sposób, że emulowane pewne bardzo podstawowe elementy OO ale wiele z tego, co chcesz robić to polegać na programistę wystający do zestawu narzuconych sobie zasad, a nie wymuszania tego przez język. A dlaczego miałbyś zawracać sobie głowę? Nie dostajesz żadnych korzyści z OO - na przykład żadnego dziedzictwa - i ograniczasz się.
Jon Hopkins,
To jest lepsza odpowiedź niż ta oznaczona jako poprawna.
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
6

„struktury” to tylko dane. Zwykle szybki i brudny test „orientacji obiektowej” brzmi: „Czy istnieje struktura, która umożliwia enkapsulację kodu i danych jako pojedynczej jednostki?”. C nie spełnia tego warunku i dlatego ma charakter proceduralny. C ++ przechodzi ten test.

Brian Knoblauch
źródło
6
Istnieją obejścia, struktury mogą mieć statyczne wskaźniki funkcji do funkcji składowych. Będą potrzebować wyraźnego thiswskaźnika, ale w takim przypadku dane i środki do przetwarzania danych zostaną zamknięte w strukturze.
Koder
@Brian Knoblauch: ale czy sam plik C nie jest enkapsulacją danych i kodu?
Dark Templar,
@DarkTemplar W pewnym sensie tak, ale jeśli nie uda ci się stworzyć jednostek tłumaczeniowych, skompiluj je i załaduj do uruchomionego procesu w czasie wykonywania, nie ma to nic dobrego.
jednostki tłumaczeniowe? >. <
Dark Templar
@Dark Templar: Jednostka tłumaczenie jest plik źródłowy oraz cokolwiek #includebyłyby do niego, a minus nic nie jest usuwane przez warunkowo włączone ( #if, #ifdefi tym podobne).
David Thornley,
5

C, podobnie jak C ++, ma zdolność zapewniania abstrakcji danych , która jest jednym z idiomów istniejącego przed nią paradygmatu programowania obiektowego.

  • Struktury C mogą zawierać dane (i to jest ich główny cel)
  • Struktury C mogą również definiować wskaźniki funkcji jako dane
  • Struktury C mogą i często mają powiązany z nimi zestaw funkcji, podobnie jak metody, tylko ten wskaźnik nie jest przekazywany niejawnie, ale należy go wyraźnie określić jako pierwszy argument każdej metody zaprojektowanej do obsługi określonej struktury. C ++ robi to automatycznie dla Ciebie, zarówno podczas definiowania, jak i wywoływania metod class / struct.

OOP w C ++ rozszerza środki na dane abstrakcyjne. Niektórzy twierdzą, że jest szkodliwy , podczas gdy inni uważają to za dobre narzędzie, jeśli są właściwie używane.

  • C ++ sprawia, że ten wskaźnik jest niejawny, ponieważ nie wymaga od użytkownika przekazywania go do „metod klasy / struktury”, o ile typ można (przynajmniej częściowo) zidentyfikować.
  • C ++ pozwala ograniczyć dostęp do niektórych metod (funkcji klasowych), a zatem pozwala na więcej „programowania obronnego” lub „ochrony przed idiotami”.
  • C ++ zachęca do tworzenia abstrakcji poprzez zapewnienie większego bezpieczeństwa typu poprzez wprowadzenie
    1. Nowy operator zamiast malloc + obsadzie
    2. Szablony zamiast pustych wskaźników
    3. Funkcje wbudowane odbierające wartości wpisane zamiast makr
    4. Wbudowany w polimorfizm, którego nie musisz samodzielnie wdrażać, co pozwala tworzyć hierarchie abstrakcji , kontrakty i specjalizacje .

Znajdziesz jednak wielu „hakerów” głoszących o tym, że C doskonale potrafi uzyskać odpowiednią ilość abstrakcji i jak narzut stworzony przez C ++ tylko odwraca ich uwagę od rozwiązania rzeczywistego problemu.

Niewystarczające abstrakcyjne modele programowania, w których dwa lata później zauważasz, że niektóre abstrakcje nie były bardzo wydajne, ale teraz cały twój kod zależy od wszystkich ładnych modeli obiektowych wokół niego i nie możesz go naprawić bez przepisywania aplikacji. -- Linus Torvalds

Inni patrzą na to w bardziej zrównoważony sposób, akceptując zarówno zalety, jak i wady.

C ułatwia strzelanie w stopę; C ++ sprawia, że ​​jest trudniej, ale kiedy to zrobisz, zdmuchnie całą nogę. - Bjarne Stroustrup

Yam Marcovic
źródło
2

Musisz spojrzeć na drugą stronę monety: C ++.

W OOP myślimy o abstrakcyjnym obiekcie (i odpowiednio projektujemy program), na przykład samochodzie, który może się zatrzymać, przyspieszyć, skręcić w lewo lub w prawo itp. Struktura z pakietem funkcji po prostu nie pasuje do tej koncepcji.

W przypadku „prawdziwych” obiektów musimy na przykład ukryć członków, lub możemy też odziedziczyć dziedzictwo z prawdziwą relacją „to” i wiele innych.

PO PRZECZYTANIU PONIŻSZYCH KOMENTARZÓW: Dobrze, że (prawie) wszystko można zrobić za pomocą C (to zawsze prawda), ale na pierwszy rzut oka pomyślałem, że to, co odróżnia c od c ++, jest sposobem myślenia podczas projektowania programu.

Jedyne, co naprawdę robi różnicę, to narzucanie zasad przez kompilator . tj. czysta funkcja wirtualna i tak dalej. ale ta odpowiedź dotyczy wyłącznie problemów technicznych, ale myślę, że główną różnicą (jak wspomniano) jest oryginalny sposób myślenia podczas pisania kodu, ponieważ C ++ zapewnia lepszą wbudowaną składnię do robienia takich rzeczy, zamiast wykonywania OOP w nieco niezdarny sposób w C.

Guy L.
źródło
Nie bardzo wiesz, dlaczego struktura z „pakietem funkcji” nie pasuje do koncepcji? +1 za odpowiedź
Dark Templar
1
Oprócz kontroli dostępu (prywatnej / chronionej / publicznej) wszystko inne można zrobić za pomocą struktur.
Koder
1
@DarkTemplar: Cóż, może próbuje naśladować OOP w C (ludzie rzeczywiście napisany e-książek na ten temat i zrobić to w świecie rzeczywistym, choć bardzo rzadko), jak można spróbować emulacji programowania funkcyjnego w Javie. Ale C zapewnia zerową pomoc, dlatego język C nie jest zorientowany obiektowo .
1

W pewnym sensie sam to powiedziałeś. Podczas gdy C ma rzeczy, które są czymś w rodzaju obiektów, nadal nie są obiektami i dlatego C nie jest uważany za język OOP.

ryanzec
źródło
1
Myślę, że pytanie brzmi: dlaczego i gdzie jest narysowana linia dla tego, co jest przedmiotem, a co nie?
Dark Templar,
1

Zorientowany obiektowo odnosi się zarówno do wzorca architektonicznego (lub nawet meta-wzorca), jak i języków, które mają funkcje ułatwiające wdrożenie lub zlecenie przy użyciu tego wzorca.

Możesz wdrożyć projekt „OO” (pulpit Gnome jest chyba najlepszym przykładem OO wykonanego w czystym C), widziałem to nawet w COBOL!

Jednak możliwość implementacji dawki projektowej OO nie czyni języka OO. Puryści twierdzą, że Java i C ++ nie są tak naprawdę OO, ponieważ nie można zastąpić ani odziedziczyć podstawowych „typów”, takich jak „int” i „char”, a Java nie obsługuje wielokrotnego dziedziczenia. Ponieważ jednak są one najczęściej używanymi językami OO i obsługują większość paradygmatu, większość „prawdziwych” programistów, którzy otrzymują wynagrodzenie za tworzenie działającego kodu, traktuje je jako języki OO.

Z drugiej strony C obsługuje tylko struktury (podobnie jak COBOL, Pascal i dziesiątki innych języków proceduralnych), można argumentować, że obsługuje wielokrotne dziedziczenie, ponieważ można użyć dowolnej funkcji na dowolnym fragmencie danych, ale większość uważa to za błąd niż funkcja.

James Anderson
źródło
0

Spójrzmy na definicję OO:

  • Wiadomości
  • Kapsułkowanie
  • Późne wiązanie

C nie zapewnia żadnej z tych trzech. W szczególności nie zapewnia przesyłania wiadomości , co jest najważniejsze.

Jörg W Mittag
źródło
1
Myślę, że musiałbym się z tym nie zgodzić. Z pewnością możesz mieć przesyłanie komunikatów w C - pracować z interfejsami API Objective C z C i dowiadujesz się o tym dogłębnie - i późne wiązanie można wykonać za pomocą wskaźników funkcji, ale nie dostajesz dużo cukru syntaktycznego, aby to ukryć. (Enkapsulacja jest w rzeczywistości łatwa w C; wskaźniki do niekompletnych typów struktur doskonale wykonują zadanie.)
Donal Fellows,
Dziedziczenie jest również uważane za ważne w OO, a C tego nie robi. Najbliższą rzeczą do enkapsulacji w C są osobne pliki, które mogą mieć staticfunkcje wewnętrzne ( ) i elementy danych.
David Thornley,
@DonalFellows, rzeczywista wiadomość przekazywana w Celu C może być łatwo zaimplementowana jako makro C99. Jedyną rzeczą, na którą idzie kompilator, jest to, że generuje wszystkie niezbędne struktury statycznie z kilku wierszy kodu wysokiego poziomu. Większość, jeśli nie wszystkie funkcje są dostępne z C API.
qpr
0

Istnieje wiele kluczowych składników do OO, ale najważniejsze to, że większość kodu nie wie, co znajduje się w obiekcie (widzą interfejs powierzchni, a nie implementację), że stan obiektu jest jednostką zarządzaną (tj. gdy obiekt przestaje być, podobnie jak jego stan), a gdy jakiś kod wywołuje operację na obiekcie, robią to, nie wiedząc dokładnie, co to za operacja lub z nią wiąże (wszystko, co robią, to kierują się wzorem „Wiadomość” nad ścianą).

C dobrze kapsułkuje; kod, który nie widzi definicji struktury, nie może (legalnie) zaglądać do niej. Wszystko, co musisz zrobić, to umieścić taką definicję w pliku nagłówkowym:

struct FooImpl;
typedef struct FooImpl *Foo;

Oczywiście będzie potrzeba funkcji, która buduje Foos (tj. Fabrykę) i która powinna delegować część pracy do samego przydzielonego obiektu (tj. Metodą „konstruktora”), a także mieć sposób ponownego pozbywania się obiektu (pozwalając mu oczyścić go metodą „destruktora”), ale to są szczegóły.

Wysyłanie metod (tj. Przesyłanie komunikatów) można również realizować zgodnie z konwencją, że pierwszy element struktury jest tak naprawdę wskaźnikiem do struktury pełnej wskaźników funkcji i że każdy z tych wskaźników funkcji musi przyjąć Fooswój pierwszy argument. Dispatch staje się wtedy kwestią wyszukania funkcji i wywołania jej z poprawnym argumentem przepisania, co nie jest takie trudne z makrem i trochę sprytne. (Ta tabela funkcji jest rdzeniem tego, czym tak naprawdę jest klasa w języku takim jak C ++.)

Co więcej, daje to również późne wiązanie: cały kod wysyłki wie, że wywołuje określone przesunięcie w tabeli wskazywanej przez obiekt. Należy to ustawić tylko podczas przydzielania i inicjowania obiektu. Możliwe jest skorzystanie z jeszcze bardziej złożonych schematów wysyłkowych, które zwiększają dynamikę działania (kosztem prędkości), ale są czereśniami oprócz podstawowego mechanizmu.

Ale to nie znaczy, że C jest językiem OO. Kluczem jest to, że C pozostawia cię do wykonania całej trudnej pracy polegającej na samodzielnym napisaniu konwencji i mechanizmu wysyłania (lub skorzystaniu z biblioteki innej firmy). To dużo pracy. Nie zapewnia również wsparcia składniowego ani semantycznego, więc wdrożenie systemu pełnej klasy (z takimi rzeczami jak dziedziczenie) byłoby niepotrzebnie bolesne; jeśli masz do czynienia ze złożonym problemem, który jest dobrze opisany przez model OO, język OO będzie bardzo przydatny przy pisaniu rozwiązania. Dodatkową złożoność można uzasadnić.

Donal Fellows
źródło
0

Myślę, że C jest w porządku i przyzwoity do wdrażania koncepcji obiektowych, wzruszając ramionami . Większość różnic, jakie widzę między podzbiorem wspólnych mianowników języków uważanych za obiektowe, są niewielkie i mają charakter składniowy z mojego rodzaju pragmatycznego punktu widzenia.

Zacznijmy od, powiedzmy, ukrywania informacji. W C możemy to osiągnąć po prostu ukrywając definicję struktury i pracując z nią przez nieprzejrzyste wskaźniki. Który skutecznie modeluje publicvs. privaterozróżnienie pól danych, ponieważ mamy z klas. Jest to dość łatwe i mało antyidiomatyczne, ponieważ standardowa biblioteka C polega na tym w znacznej mierze w celu ukrycia informacji.

Oczywiście tracisz możliwość łatwego kontrolowania, gdzie struktura jest przydzielona w pamięci za pomocą nieprzezroczystych typów, ale to tylko godna uwagi różnica między, powiedzmy, C i C ++. C ++ jest zdecydowanie lepszym narzędziem do porównywania jego zdolności do programowania obiektowych pojęć nad C przy jednoczesnym zachowaniu kontroli nad układami pamięci, ale to niekoniecznie oznacza, że ​​Java lub C # jest lepszy od C pod tym względem, ponieważ te dwa sprawiają, że jesteś całkowicie tracą możliwość kontrolowania, gdzie obiekty są przydzielane w pamięci.

I musimy użyć składni takiej fopen(file, ...); fclose(file);jak w przeciwieństwie do file.open(...); file.close();dużego whoop. Kogo to obchodzi? Może po prostu ktoś, kto mocno opiera się na autouzupełnianiu w swoim IDE. Przyznaję, że może to być bardzo przydatna funkcja z praktycznego punktu widzenia, ale może nie taka, która wymaga dyskusji na temat tego, czy język jest odpowiedni dla OOP.

Brakuje nam możliwości skutecznego wdrażania protectedpól. Całkowicie się tam złożę. Ale nie sądzę, aby istniała konkretna zasada, która mówi: „ Wszystkie języki OO powinny mieć funkcję umożliwiającą dostęp do podklas członkom klasy podstawowej, do których normalni klienci nadal nie powinni mieć dostępu ”. Poza tym rzadko widuję przypadki użycia dla chronionych członków, którzy nie są co najmniej trochę podejrzliwi, aby stać się przeszkodą w utrzymaniu.

I oczywiście mamy do „emulować” oo polimorfizmu z tabelami wskaźników funkcji i wskaźniki do nich do dynamicznego wysłania trochę więcej boilerplate zainicjować te analogiczna vtablesa vptrs, ale trochę boilerplate nigdy nie sprawiało mi wiele smutku.

Dziedziczenie jest bardzo podobne. Możemy łatwo modelować to poprzez kompozycję, a przy wewnętrznym działaniu kompilatorów sprowadza się to do tego samego. Oczywiście tracimy bezpieczeństwo typu, jeśli chcemy obniżyć , i powiedziałbym, że jeśli chcesz być w ogóle obniżony , nie używaj do tego C, ponieważ rzeczy, które ludzie robią w C, aby emulować obniżanie, mogą być przerażające z punktu widzenia bezpieczeństwa, ale wolałbym, żeby ludzie wcale nie byli przygnębieni . Bezpieczeństwo typu jest czymś, czego łatwo można przeoczyć w C, ponieważ kompilator zapewnia tyle swobody interpretacji rzeczy jak tylko bity i bajty, poświęcając zdolność do wychwytywania potencjalnych błędów w czasie kompilacji, ale niektóre języki uważane za obiektowe nie są są nawet wpisywane statycznie.

Więc nie, myślę, że jest w porządku. Oczywiście nie użyłbym C, aby stworzyć bazę kodu na dużą skalę, która byłaby zgodna z zasadami SOLID, ale niekoniecznie z powodu jej niedociągnięć w froncie zorientowanym obiektowo. Wiele funkcji, których brakowałbym, gdybym próbował użyć C do takiego celu, byłyby związane z funkcjami języka, które nie są bezpośrednio uważane za warunek wstępny dla OOP, takie jak silne bezpieczeństwo typu, destruktory, które są automatycznie wywoływane, gdy obiekty wykraczają poza zakres, operator przeciążenie, szablony / ogólne i obsługa wyjątków. Właśnie wtedy brakuje mi dodatkowych funkcji, które sięgam po C ++.


źródło
1
Nie jestem pewien, w jaki sposób konstruktorów nie można uznać za warunek wstępny dla OOP. Częścią podstawowej istoty enkapsulacji jest zdolność do zapewnienia niezmienników dla obiektu. A to wymaga właściwej inicjalizacji obiektu w tych niezmiennikach. Wymaga to konstruktora: jedna lub więcej funkcji, tak że nie można powiedzieć, że obiekt istnieje, dopóki przynajmniej jedna z nich nie zostanie wywołana.
Nicol Bolas,
Gdy mamy informacje ukrywające się w typach nieprzezroczystych, jedynym sposobem na ich utworzenie i skopiowanie / sklonowanie i zniszczenie jest zastosowanie analogicznego odpowiednika funkcji służących jako konstruktory i destruktory z taką samą zdolnością do utrzymania tych niezmienników. To po prostu nie jest bezpośrednio wzorowany na język i może przypominać formę foo_createi foo_destroya foo_clone, np
W struct Footakim przypadku musimy jedynie zachować niezmienniki, aby upewnić się, że dostęp do jego członków danych nie będzie możliwy i zmutowany przez świat zewnętrzny, który typy nieprzezroczyste (zadeklarowane, ale nie zdefiniowane dla świata zewnętrznego) natychmiast dają. Jest to prawdopodobnie silniejsza forma ukrywania informacji, na równi z tą pimplw C ++.
Tak, wiem, jak ludzie wdrażają OOP w C, dziękuję. Chodzi mi o to, że twoje stwierdzenie, że konstruktory „nie są bezpośrednio uważane za warunek wstępny dla OOP”, jest błędne.
Nicol Bolas,
Rozumiem, daj mi rację, ale czy w takim przypadku możemy powiedzieć, że C zapewnia (odpowiednie?) Wsparcie dla destruktorów i konstruktorów?
-1

Niezłe pytanie.

Jeśli zamierzasz nazwać język OO, musisz zadzwonić prawie do wszystkich języków proceduralnych OO. Czyni to termin bez znaczenia. c nie obsługuje języka dla OO. Jeśli ma struktury, ale struktury typesnie są klasami.

W rzeczywistości c nie ma wiele funkcji w porównaniu do większości języków. Jest używany głównie ze względu na szybkość, prostotę, popularność i wsparcie, w tym mnóstwo bibliotek.

Glen P.
źródło