Programowanie obiektowe w inny sposób

0

Wbrew pozorom język C daje większe możliwości swobodnego podejścia do programowania obiektowego niż język C++. Zauważyłem, że podawane tutaj przykłady głównie pokazują, jak naśladować C++ w języku C. Natomiast język C nie posiada ograniczenia zamknięcia danych w ciele klasy i umożliwia na przykład odwoływanie się do tych samych danych przez przez funkcje, które można by zgrupować jako przynależne do dwóch obiektów programowania zorientowanego obiektowo w C.

struct Dane
{ unsigned id;
  char *nazwa;
};
struct Dane2
{ unsigned id;
  char *etykieta;
};
struct Dane *dane;
unsigned dane_n;
struct Dane2 *dane2;
unsigned dane2_n;

//po przydzieleniu pamięci konstruktorem i ustawieniu liczby elementów w tablicy...

char *
etykieta_dla_nazwy( struct Dane *dane, struct Dane2 *dane2, char *nazwa
){  for( unsigned i = 0; i != dane_n; i++ )
        if( !strcmp( nazwa, dane[i].nazwa ))
            for( unsigned j = 0; j != dane2_n; j++ )
                if( dane[i].id == dane2[j].id )
                    return dane2[j].etykieta;
    return 0;
}

To jest trywialny przykład, ale obrazuje, jak można przechowywać dane, by ich nie kopiować w czasie wykonywania programu, by ich niepotrzebnie nie powielać.
Jest to przykład nawiązujący do kolekcji obiektów i ewentualnie relacyjnych baz danych.
Istnieją inne metodologie programowania obiektowego niż zamknięte klasy hierarchiczne albo obiektowość otwarta, jak na przykład w Javascript, gdzie również przypisuje się funkcje do wnętrza obiektów.
Pytanie tylko, jakie to metodologie programowania. Gdzie mógłbym zacząć szukać, chcąc zachować szybkość C, a programować obiektowo w sposób opisany powyżej z zabezpieczeniem przed błędami lepszym niż w C?

1
overcq napisał(a):

To jest trywialny przykład, ale obrazuje, jak można przechowywać dane, by ich nie kopiować w czasie wykonywania programu, by ich niepotrzebnie nie powielać.
Jest to przykład nawiązujący do kolekcji obiektów i ewentualnie relacyjnych baz danych.

Nie rozumiem, co z tymi kolekcjami i bazami ???

Istnieją inne metodologie programowania obiektowego niż zamknięte klasy hierarchiczne albo obiektowość otwarta, jak na przykład w Javascript, gdzie również przypisuje się funkcje do wnętrza obiektów.

Tzw obiektowość dynamiczna.
Pewnie jakbym musiał, to bym zrobił w C?C++.
Zresztą ma to Python, zrealizowany przecież w C.

Pytanie tylko, jakie to metodologie programowania. Gdzie mógłbym zacząć szukać, chcąc zachować szybkość C, a programować obiektowo w sposób opisany powyżej z zabezpieczeniem przed błędami lepszym niż w C?

Odpowiedź jest prosta, w C++.
Nadzieja na "mój zarąbisty najszybszy na świecie kod C" jest typowa dla początkujących i elektroników.
To, co bywa wolne w C++, nie wynika z jego istoty, tylko z realizowania bardziej ambitnych problemów, niż ktokolwiek by umiał zrobić bezpiecznie w C.

Nie jest dla mnie jasne, jaki zamiar tu realizujesz (jaki konkretnie wzorzec/element zachowania obiektowego), i w czym widzisz sukces.

To, że w C można realizować istotne elementy programowania obiektowego, to się zgodzę.
Sam będąc "młodszym programistą" (młodszym tzn dość dawno temu) jeszcze w C, gdy C++ jeszcze nie zawitało (netu nie było, tylko koledzy z kserami) , wynalazłem metody wirtualne, bo było mi potrzebne.

6
overcq napisał(a):

Gdzie mógłbym zacząć szukać, chcąc zachować szybkość C, a programować obiektowo w sposób opisany powyżej z zabezpieczeniem przed błędami lepszym niż w C?

Rust?

0

Im dłużej patrzę w ten przykładowy kod tym bardziej nie widzę gdzie tu polimorfizm. Widzę tylko dwie tablice różnych struktur.
Jak robić bezpieczniej polimorfizm w C? Są do tego biblioteki. Chyba najbardziej znaną jest GObject od Gnome. Ale to tylko proteza więc lepiej wziąć język który już ma polimorfizm wbudowany jak np. Rust

2

W tym przykładzie w jednej tablicy znajdujesz sobie obiekt mający pole nazwa, z tego obiektu wyciągasz sobie id i w drugiej tablicy znajdujesz obiekt mający takie samo id i wyciągasz z niego wartość etykieta. Ja tu nie dostrzegam rzeczy nieosiągalnych w C++ ani oop. Obiektowe programowanie w C polega z tego co widziałem na zrobieniu w strukturze interfejsu w postaci function pointerów i w funkcji pełniącej rolę konstruktora przypisanie do nich właściwych implementacji.

3
overcq napisał(a):

Wbrew pozorom język C daje większe możliwości swobodnego podejścia do programowania obiektowego niż język C++.
Może by i dawał tylko że znacznie lepsze efekty da algorytmika oraz struktury danych:

struct Dane
{
	unsigned id;
	char *nazwa;
	char *etykieta;
};
struct Table
{
	size_t count;
	struct Dane *tb;
};
const char *etykieta_dla_nazwy( struct Table tb,char *nazwa)
{
	for(size_t i=0;i<tb.count;++i) if(!strcmp(nazwa,tb->tb[i].nazwa)) return tb.tb[i].etykieta;
	return 0;
}

Zauważ że teraz zamiast kosztu kwadratowego O(N*N) masz liniowy O(N).
A jeżeli posortujesz wg nazw to będzie koszt logaritmiczny log(N)
A jak w C++ użyjesz map<string,string> to koszt będzie O(1)
Więc gdzie ty widzisz tu przewagę?

overcq napisał(a):

Pytanie tylko, jakie to metodologie programowania. Gdzie mógłbym zacząć szukać, chcąc zachować szybkość C, a programować obiektowo w sposób opisany powyżej z zabezpieczeniem przed błędami lepszym niż w C?

Najpierw naucz się programowania obiektowego chociażby po łebkach (byle kurs w google).
A potem odpowiedź sama przyjdzie.

Owszem są pewne rzeczy które da się zrobić w C, zaś w C++ tyko używając malloc'a z C.
Np zliczanie liczby słów z pliku:

typedef struct _Node
{
	struct _Node *lf,*rt;
	size_t count;
	char word[1];
} Node;

void put(Node **node,const char *word)
{
	int cmp,size;
	while(*node)
	{
		cmp=strcmp((*node)->word,word);
		if(cmp>0) node=&((*node)->lf);
		else if(cmp<0) node=&((*node)->rt);
		else
		{
			++(*node)->count;
			return;
		}
	}
	size=strlen(word);
	*node=(Node*)malloc(sizeof(Node)+size);
	(*node)->lf=(*node)->rt=0;
	(*node)->count=1;
	memcpy((*node)->word,word,size+1); 
	// tu przydało by się równoważenie drzewa
}

Każdy węzeł w powyższym przykładzie ma inny rozmiar, co ma swoje ewidentne zalety.

0

Przeglądnąłem tak na szybko dokumentację Rust i rzeczywiście ma on odzielone dane obiektu od funkcji obiektu. Tylko że na razie jeszcze nie znalazłem, jak zaimplementować różne impl dla tej samej struct, może poza Traits, które robi tylko coś podobnego do tego, ale nie to samo. Będę dalej szukał rozwiązania...

0
overcq napisał(a):

Przeglądnąłem tak na szybko dokumentację Rust i rzeczywiście ma on odzielone dane obiektu od funkcji obiektu. Tylko że na razie jeszcze nie znalazłem, jak zaimplementować różne impl dla tej samej struct, może poza Traits, które robi tylko coś podobnego do tego, ale nie to samo. Będę dalej szukał rozwiązania...

Wreszcie rozumiem o co Ci chodzi. Takie rzeczy jak utworzenie nowej klasy bez alokacji to tylko w Haskellu :P i językach które się nim inspirują

  • w Haskellu jest konstrukcja newtype o składni newtype MyNewType = MyNewType OldType
  • w Scali jest class MyNewClass(value: OldType) extends AnyVal
  • w Ruscie jest New Type Idiom o składni pub struct MyNewType(OldType)

Dzięki temu możesz mieć dwie impelentacje zachowania dla tych samych danych

1 użytkowników online, w tym zalogowanych: 0, gości: 1