Kontrola statyczna i rozpoznawanie typów zmiennych - RTTI


(Quentin) #1

Witam!

Ostatnio czytałem o narzędziu pozwalającym porównywać typy danych, czyli o operatorze typeid zaimplementowanym w RTTI. Postanowiłem przeczytać cały artykuł (http://www.google.pl/url?sa=t&source=we ... azz42RQTag) o tym, żeby przy okazji dowiedzieć się czegoś więcej o klasie type_info i mam kilka innych pytań:

Pytanie 1.

Nie wiem o co chodziło dokładnie z tymi konstrukcjami programowymi - wiem, że np. nie jest sprawdzana legalność przy operacji np. odniesienie się do 77 el. tablicy, która ma el. 10 - ale nie wiem czemu tak się dzieje dokładniej. Po za tym jak można w cytacie przeczytać, jeżeli naruszymy system typów, program nie skompiluje się. Więc gdyby tą silną typizację zaimplementowano w C++ zamiast tej zwykłej kontroli statycznej to co by się zmieniło ? Np. taka legalność przy tablicach :?:

Pytanie 2.

Ta konwersja dynamiczna robiona operatorem dynamic_cast różni się od static_cast (konwersji statycznej), że jeżeli coś ze static_cast nie wypali - błąd kompilacji. Dynamic_cast zwraca po prostu adres wskaźnika lub NULL do wskaźnika. I nazywa się to konwersją dynamiczną tylko dlatego, że operator ten "uczy się jakby tej hierarchii", ponieważ gdzieś w klasie jest funkcja wirtualna (bo musi być do tego) i jest jakby operatorem "polimorficznym" :?:

Pytanie 3.

Czy ktoś mógłby wytłumaczyć co robi w takim razie taka funkcja, bo na początku też mi przyszło do głowy, że zajmuje się hierarchiami :?:

Np. na:

:arrow: http://www.intercon.pl/~sektor/cbx/advanced/rtti.html

Jeżeli chodzi o różnicę adresów to przychodzi mi do głowy tylko jeden pomysł. W tym artykule co dałem na początku link, jest napisane, że operator typeid zwraca obiekt klasy type_info. I wg mnie w tej funkcji before po prostu porównują dwa adresy:

746835 < 9824434

I teraz by ta funkcja zwróciła true, bo pierwszy obiekt typu type_info został utworzony wcześniej niż drugi, ponieważ komórka w pamięci gdzie on się znajduje ma adres mniejszy niż ten drugi obiekt. O to chodzi w tej funkcji :?:

Pytania są trochę duże, ale myślę, że ktoś postara się odpowiedzieć :slight_smile:

Z góry wielkie dzięki :wink:


(Fiołek) #2

W C++ nie da się zaimplementować "silnej typizacji" ponieważ jest coś takiego jak wskaźnik, do tego jest coś takiego jak wskaźnik na void(typ nieokreślony), istnieje rzutowanie wskaźników(można ze string* zrobić int* bez żadnego problemu).

Co do tablic: dzieje się tak, ponieważ kompilator "przerabia" odwołanie do elementu tablicy na coś takiego:

tablica[10] = tablica + 10 = tablica(void*) + sizeof(typ_tablicy) * 10

(nigdzie nie zna rozmiaru tej tablicy).

dynamic_cast nie zwróci null-a tylko wtedy jeśli obiekt jest danej klasy lub dziedziczy z tej klasy. Przykład:

class A{ virtual void TestowaFunkcja(){}};

class B : public A{};

class C : public B{};

class D : public C{};

class E : public D{};


D* Funkcja(A *obiekt)

{

	return dynamic_cast(obiekt); //Jeśli obiekt jest klasy "d" nie zwróci null-a, jeśli jest innej - będzie null.

}


int main()

{

	C obiekt;

	D* wsk = Funkcja(&obiekt); //Będzie null;


	D obiekt2;

	wsk = Funkcja(&obiekt2); //Nie zwróci null-a.


	E obiekt3;

	wsk = Funkcja(&obiekt3); //Nie będzie null-a.

}

(Quentin) #3

Aha, czyli w C++ pomimo kontroli statycznej można rzutować, ale kiedy była by to silna (słowo mówi samo za siebie) typizacja to takiego rzutowania nie można było by robić ? Dobrze rozumiem :?:


(Fiołek) #4

W "silnej typizacji" też można rzutować, jeśli rzutowanie jest dozwolone(np. jest operator rzutowania albo jest to proste rzutowania typu double -> int, int - > long(64-bit), int ->double).


(Quentin) #5

No więc nie można było by robić rzutowania wskaźników, ponieważ czasem nie są dozwolone :?:


(Fiołek) #6

Jeśli typ na który byśmy rzutowali byłby wyżej w hierarchii dziedziczenia to byłoby to dozwolone. Jeśli nie to nie.


(Quentin) #7

Nie wiem czy wiesz o co mi chodzi. Wiem, że jeżeli byłby niżej to byłby to błąd, ale piszesz:

Więc wychodzi na to, że w językach gdzie istnieje "silna typizacja" nie ma wskaźników i czegoś takiego jak rzutowanie reinterpret_cast , które pracuje na wskaźnikach...


(Fiołek) #8

Może źle się wyraziłem... Wskaźnik może istnieć, ale nie można rzutować wskaźnika na typ nie istniejący w hierarchi.


(Quentin) #9

Aha już kapuję, nawet jeżeli nic by się tam nie zapisywało w to miejsce tak jak np. przy funkcji write na char* w ostream, gdzie potrzebny jest po prostu sam adres. I wobec tego w takich językach zastępują to np. szablonami jak podejrzewam. OK to dzięki za pomoc :slight_smile: