🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.objects
Article #4810

OO Fack you

#4810
From: Sektor van Skijlen
Date: Tue, 26 Jan 1999 15:22
403 lines
13963 bytes
Przejrzalem ostatnio oofaq, ktore jakis czas temu sciagnalem z tej listy i
nasunelo mi sie pare komentarzy.

*****
Na wstepie - proponowalbym umiescic informacje o wszystkich obiektowych
jezykach programowania, jakie obecnie sa w uzyciu. Na razie opisane zostaly
C++ i Smalltalk. Moze warte opisania bylyby tez Java, Eiffel, Python, czy
ObjectiveC. Poza tym rad bym tez znalezc wiecej informacji o O++ czy R++,
jesli ktos czyms takim dysponuje.
*****

-------
T.1.2	Proponowany maly slownik terminow.

  garbage collector    - odsmiecacz
  operator overloading - przeciazanie operatora
  object persistency   - trwanie obiektu
  persistent pointer   - trwaly wskaznik
  container            - pojemnik
  template             - szablon
  reference            - odnosnik
**** odniesienie - odnosnik to by bylo "referer"
  dereferencing        - wyluskiwanie


-----
T.1.5	Co to jest atrybut?

Atrybut to cecha obiektu, na przyklad kolor pojazdu, dlugosc tekstu,
wzrost osoby. Atrybuty sa innymi obiektami zagniezdzonymi w danym
obiekcie.

****
Z tego, co wiem, w C++ nazywa sie to polami. Domyslam sie, ze to jest
slownictwo dla ogolnie OO, ale wydaje mi sie, ze o tym nalezaloby wspomniec.
****

-----
T.1.11	Co to jest metaklasa?

Metaklasa to jakby klasa dla klasy, innymi slowy, egzemplarze
(instance) metaklas sa klasami. Metaklasy wystepuja nie we wszystkich
jezykach programowania, a nawet w tych, w ktorych wystepuja, trudno
wskazac ich konkretne, programistyczne zastosowanie. Jednakze czesto
stosuje sie jej nawet o tym nie wiedzac.

****
Nt. metaklas dotychczas wyobrazalem sobie cos takiego, ze jest to obiekt
stworzony na uzytek klasy. To znaczy zawierajacy konkretne atrybuty (takze
zmienne), ktore determinuja klase.
****

-----
T.1.12	Co to jest komponent?

Komponent to grupa klas, ktore sluza jednemu, konkretnemu celowi.
Klasy w komponencie charakteryzuja sie tym, ze maja silne powiazania
z innymi klasami wewnatrz tego samego komponentu i slabe poza nim.
Dzieki temu komponent moga byc rozwijane niezaleznie i podmieniane w
razie potrzeby, bez modyfikacji innych komponentow. Przykladem
komponentu moglaby byc grupa klas odpowiedzialna za obsluge wydruku.

****
Jak sie to ma do jezykow programowania ? Przydalby sie tutaj jakis konkretny
przyklad w jakims konkretnym jezyku (takim, ktory takie komponenty
implementuje). Chocby teoretycznie i z grubsza.
****

-----
T.1.13	Co to sa obiektowe bazy danych?

Pojecie "bazy danych" nie jest szczegolnie szczesliwe. Lepiej mowic o
"obiektach trwalych". Systemy takie pozwalaja na przechowanie stanu
obiektu pomiedzy wywolaniami aplikacji, czyli tak, jak tradycyjna
baza danych przechowuje dane. Jednakze roznica miedzy nimi a takimi
bazami polega na fakcie, ze nie trzeba programowo odtwarzac stanu
aplikacji z bazy (np. zapytaniami SQL). Po prostu obiekty aplikacji i
obiekty bazy danych to to samo.

****
Przyznam, ze nic z tego nie rozumiem. Jak to sie realizuje ?
****



-----
T.2.1	Jak w prosty sposob zrozumiec opis bledu w BC++?

Przeczytac opis bledu, zajrzec do "Programmer's Manual",
"Programmer's Reference", podrecznika C++.
Jesli nie pomoze, skontaktowac sie z innymi osobami piszacymi w C++.

****
To chyba jakis zart :*))
Czy na pewno jest sens w ogole umieszczania informacji o konkretnych
kompilatorach ?
****

-----
T.2.2	Co zrobic jesli klasa deklarowana w pliku naglowkowym uzywa typow
	deklarowanych w innych plikach naglowkowych?

W _kazdym_ pliku naglowkowym nalezy wpisac:

#ifndef nazwapliku_h
#define nazwapliku_h
..
#endif

I mozesz bezkarnie wlaczac potrzebne ci headery.

****
Przepraszam, o czym my w ogole mowimy ? Toz to sa takie podstawy, ze az
smieszne...
****

-----
T.2.3	Co to sa dziwne pliki w katalogu "/usr/g++-include/gen" z
	roszerzeniami ".ccP" oraz ".hP"?

Jest to po prostu biblioteka "libg++". Dowiedziec sie czegos wiecej mozesz
z dokumentacji. A pliki z rozszerzeniem ".ccP" i ".hP" sa wejsciowymy
plikami do programu "genclass". To sa pliki ze starej wersji kompilatora,
ktory nie mial wlaczonych templates, wiec uzywalo sie tego i "genclass"
specyfikujac jaki mial byc bazowy typ, "genclass" tworzyl z tego pliki
np. "<type>Vec.cc" i "<type>Vec.h" zastepujac <T> podanym typem.

****
Przyznam, ze interesowala mnie ta informacja i fajnie, ze sie dowiedzialem.
Niemniej podejrzewam, ze to juz nie jest istotne.
****

-----
T.2.4	Jak w C++ obsluguje sie funkcje ze zmienna liczba parametrow?

W starym C stosowalo sie <varargs.h>, w nowym (ANSI C oraz C++)
stosuje sie <stdarg.h>.

Ponizej przyklad programu wykorzystujacy <stdarg.h>.
 va_list   - typ zmiennej pomocniczej
 va_start  - inicjalizacja listy
 va_argptr - przesuniecie wskaznika listy na nastepny element

#include <stdio.h>
#include <stdarg.h>

void pisz(char *tekst,...)
{
va_list argptr;

  va_start(argptr,tekst);
  printf("\nTo sa dane : %s",tekst);
  while(*(tekst=va_arg(argptr,char *))!=NULL)
    printf(" %s",tekst);
  va_end(argptr);
};

void main()
{
  pisz("ala","ola","kot","domek na prerii","i nic",NULL);
};

Typowo to jest tak, ze pierwszy parametr zawiera informacje o liczbie
dalszych parametrow. Moze to byc liczba, ale moze byc tak jak w "printf":
  printf("zmienna %s = %d",...)
Tu jest podane, ze tylko dwoch parametrow trzeba sie doszukac.

****
Male przypomnienie wiec. W AmigaDOSie istnieje taka funkcja, ktora sie nazywa
OpenWindow (jak sama nazwa wskazuje, sluzy do...), ktore dostawala bardzo duzo
parametrow i nalezalo pamietac ich typy i kolejnosc (oraz podac wszystkie - to
bylo w C). W wersji 2.0 wymyslono drobna modyfikacje - OpenWindowTags. Uzywalo
sie tego w ten sposob:

Window* w = OpenWindowTags( 0,
		WA_TOP, 20,
		WA_LENGTH, 40,
		WA_DEPTH, 4,
		WA_FLAGS, NOSIZE,
		TAG_DONE );

Byla to bardzo uzyteczna rzecz, acz C++ stac na cos lepszego.

Przypuszczalnie mamy taka strukture:

class Window
{
	Window* parent;
	size_t wd, ht, dp;
	WFlags flg; // przypuscmy, ze zdefiniowane
	// reszta danych...

		public:
	Window( Window* par )  // konstruktor bezparametrowy - inicjalizuj domyslne
	: parent( par ), wd( 20 ), ht( 40 ), dp( 4 ), flags( none )
	{}

	Window& Top( size_t settop )
	{
		ht = settop;
		return *this;
	}

	Window& Length( size_t ln )
	{
		wd = ln;
		return *this;
	}

	Window& Flags( WFlags wflg )
	{
		flg = wflg;
		return *this;
	}
	// itd.
};


I to mozna wywolac w ten sposob:

	Window w( 0 )
		.Top( 20 )
		.Length( 23 )
		.Flags( Window::nosize );
		

Ewentualnie przez wskaznik.

Spadku efektywnosci dobry kompilator wykazac nie powinien - bedziemy miec
wtedy ciag przypisan:

ht = 20;
wd = 40;
ht = 20
wd = 23;

i dobry kompilator powinien te dwa pierwsze przypisania opuscic.

Druga rzecz - mozna uzywac przeciazonych operatorow. Przyklad mamy chyba jeden
z jasniejszych w samej bibliotece iostream. Poza tym kiedys sie bawilem w cos
takiego:

print, 2, " to jest wiecej, niz ", 1, '\n';

:*)
Nawet dla zartu moglibysmy przy tworzeniu takiej biblioteki napisac w
dokumentacji, ze sa to takie specjalne funkcje, ktore oznaczamy przez % na
koncu:

print% 2, " to jest wiecej, niz ", 1, '\n';

Oba te sposoby sa duzo lepszym i bezpieczniejszym sposobem tworzenia w C++
funkcji o zmiennej liscie parametrow (ten drugi ma tylko ta wade, ze konieczne
jest uzywanie buforowania, gdyz wywolanie mamy za kazdym parametrem, co
powoduke koniecznosc uzywania znacznika, oznaczajacego, ze zakonczylismy
podawac parametry i nalezy wykonac akcje - w iostream tym znacznikiem jest
znak '\n' - niemniej i tak jest lepszy, niz tamten).

Przy okazji ciekawostka - naglowek 'int funkcja(...)' nakazuje kompilatorowi
olac rodzaj przyjmowanych parametrow (nie jak w C int funkcja() ).
****
	

-----
T.2.6	Czy stosowanie zaprzyjazniania klas nalezy do dobrej praktyki
	programisty?

Nie, gdyz dopuszcza do latwego dostepu do pol prywatnych i
chronionych. Narusza to zasade "jedyna aktywnosc systemu
obiektowego to przekazywanie wiadomosci (message passing)". Istnieje
roznica miedzy zapisaniem "kolo->radius=5;", a "kolo->setRadius(5);".

****
Sadze, ze ocenianie, czy stosowanie lub nie friend nalezy do dobrej praktyki,
jest niestety dyskutowaniem o gustach. Swego czasu byla mowa o zaprzyjaznianiu
klasy. Oczywiscie, ze mozna uzyc tego w stosunku do klasy i wlasnie nazwalbym
to przyznawaniem praw, a nie naruszaniem enkapsulacji. Jesli mamy klase, w
ktorej mamy konstruktor prywatny, to jesli przyznamy innej klasie frienda do
niej, to staje sie ona prywatna dla niej. Konkretnie:

class klasa0
{
	klasa0(){}
	friend class klasa1;
};

class klasa1
{
	klasa0 o0;
};

W tym przykladzie, klasa0 staje sie prywatna klasa klasy klasa1. Co w praktyce
oznacza, ze obiekty klasa klasa0 sa przeznaczone do uzywania tylko przez klase
klasa1.

Pytanie, czy nie wystarczy zadeklarowac ta klase wewnatrz klasy klasa1. Otoz
nie zawsze, gdyz friend pozwala na to, by klasa0 byla prywatna klasa nie tylko
klasa1, ale tez kilku innych.

Pytanie do grupowiczow: czy dla tego rozwiazania sa lepsze alternatywy (jasne,
ze mozna dobrac inna filozofie projektu, ale ja pytam, jak TA zrealizowac).
****


-----
T.2.10	Czy istnieje domyslny konstruktor kopiujacy?

Tak - kopiuje poszczegolne pola. Z tego powodu nie nadaje sie
do klas zawierajacych wskazniki - w efekcie otrzymujemy dwa obiekty
wskazujace na ten sam (trzeci) obiekt. Jezeli teraz jeden z tych
obiektow zostanie usuniety, to najprawdopodobniej zostanie tez
zniszczony obiekt przez niego wskazywany, i drugi z obiektow bedzie
wskazywal cos blednego. Dlatego tez gdy uzywamy operacji przypisania,
a dana klasa zawiera wskazniki, to trzeba konstruktor kopiujacy
zdefiniowac samemu, umieszczajac w nim operacje potrzebne do
utworzenia kopii obiektu wskazywanego przez wskaznik.

****
Racja, ze kopiuje poszczegolne pola i racja rowniez, ze nie nadaje sie do
wskaznikow. Ale prosze wyraznie zaznaczyc, ze konstruktor kopiujacy korzysta z
operatorow przypisania dla poszczegolnych pol. Jesli przykladowo mamy w
klasie pole typu string, to dla niego wywola sie normalnie operator
przypisania (a nie skopiuje sie wskaznik).
****

-----
T.2.11	Jak uniknac dolaczania metod wirtualnych, z ktorych nie korzystam, a
	sa zadeklaroawne w definicji objektu?

Pozne laczenie ("late binding"), ktore UMOZLIWIA tworzenie metod
wirtualnych, polega wlasnie na tym, ze program w momencie kompilacji
i linkowania _nie wie_, ktore metody beda mu potrzebne. Inna sprawa ze
zwyklymi metodami.

****
W jakim jezyku jest to realizowane (i jak tego uzywac) ?
****

-------
T.2.13	Stosowac wskaznik czy referencje?

Istnieja zasadnicze roznice miedzy wskaznikiem, a referencja:
	1. Referencje nie moga byc puste
	2. Raz ustawionej referencji nie mozna przeniesc na inny obiek
	3. Nie mozna zrobic referencji do referencji, tak jak robi sie
	wskaznik do wskaznika.
Generalnie, lepiej jest stosowac referencje. Jednakze jezeli z wyzej
wymienionych powodow jest to niemozliwe, to nalezy zastosowac
wskaznik.

****
Referencja nie jest zwyklym typem. Mimo, iz czesto wystepuje w programach
fizycznie, to nie nalezy o niej myslec w kategorii wskaznikow, lecz w
kategorii tego, do czego sie odnosza. Z punktu widzenia jezyka JEST ona
aliasem do obiektu (acz nie dynamicznym, jesli bedzie to referencja do
obiektu, ktory jest wskazywany przez wskaznik, to sam wskaznik nie jest
parametrem dla tego aliasa, tylko obiekt, na jaki w momencie inicjalizacji
wskazywal wskaznik).
****

-------
T.2.15	Czy wszystkie metody w mojej klasie powinny byc wirtualne?

W zasadzie tak. Deklarujac metode jako niewirtualna uniemozliwiasz
zmiane jej implementacji w klasie dziedziczacej, a tym samym zawezasz
elastycznosc swojego systemu.

****
Nie nalezy mowic, ze "w zasadzie tak". Cale to nastepne zdanie jest bez sensu.
Zwykle projektujac program, zaklada sie, jakie metody moga byc pozniej
zaslaniane w innych obiektach. Wrecz liczba metod wirtualnych powinna byc jak
najmniejsza; nie ma sensu tworzyc metod wirtualnych, jesli nie przewidujemy
jej zaslaniania. Metody wirtualne przeciez determinuja polimorficznosc
obiektow; deklarowanie metod wirtualnych, ktore nie zostana zasloniete tylko
wprowadza projekt w blad.
****


-------
T.2.16	Czy konstruktory moga byc wirtualne?

Nie. Ale mozna stworzyc odpowiednik konstruktora wirtualnego. Opisuje
to wzorzec Abstract Factory z ksiazki "Design Patterns", Gamma et al.

****
Nie widze zastosowania, szczerze mowiac. Przeciez i tak kazda klasa dysponuje
wlasnym konstruktorem, a konstruktora nie mozna wywolac na rzecz obiektu
wskazywanego przez wskaznik (do klasy bazowej, czy innej). Konstruktor jest
wywolywany po przydzieleniu pamieci na obiekt, a przed pierwszym uzyciem
obiektu. Tzn... w zasadzie (na upartego) mozna, ale nie nalezy. W
konstruktorze bowiem zawsze z reguly zaklada sie, ze pola nie zostaly jeszcze
zainicjalizowane (np. nie zostala przydzielona pamiec). W C++ zamiast tego
stosuje sie metode inicjalizujaca, ktorej uzywa konstruktor i operator
przypisania.
****


To by bylo na tyle na razie.

-- 
[- Ben a dar van dijn vijt -]
Michal 'Sektor' Malecki <mmalecki@technologist.com>
Politechnika Lodzka, Elektrotechnika/Informatyka st.
Technical Details
Message-ID: <78kmj5$abm$4@polonez.man.lodz.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!pingwin.icm.edu.pl!mat.uni.torun.pl!news.man.torun.pl!news.icm.edu.pl!news.man.poznan.pl!news.man.lodz.pl!not-for-mail

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!pingwin.icm.edu.pl!mat.uni.torun.pl!news.man.torun.pl!news.icm.edu.pl!news.man.poznan.pl!news.man.lodz.pl!not-for-mail
From: Sektor van Skijlen <sektor@spam.org>
Newsgroups: pl.comp.objects
Subject: OO Fack you
Date: 26 Jan 1999 15:22:13 GMT
Lines: 403
Message-ID: <78kmj5$abm$4@polonez.man.lodz.pl>
NNTP-Posting-Host: zly.kis.p.lodz.pl
User-Agent: tin/pre-1.4-981225 ("Volcane") (UNIX) (SunOS/5.5.1 (i86pc))
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit