Chirurgia endoscopică a hipofizei
"Standardul de aur" în chirurgia hipofizară îl reprezintă endoscopia transnazală transsfenoidală. Echipa NeuroHope este antrenată în unul din cele mai mari centre de chirurgie a hipofizei din Europa, Spitalul Foch din Paris, centrul în care a fost introdus pentru prima dată endoscopul în chirurgia transnazală a hipofizei, de către neurochirurgul francez Guiot. Pe lângă tumorile cu origine hipofizară, prin tehnicile endoscopice transnazale pot fi abordate numeroase alte patologii neurochirurgicale. www.neurohope.ro |
Virtual tabele and _vptr
Last Updated: Jan 23 2018 12:51, Started by
virgil94
, Jan 15 2018 14:01
·
0
#1
Posted 15 January 2018 - 14:01
Salut,
Am intrat putin in detalii despre cum functioneaza desturctorii virtuali. Am citit ce a scris colegul aici si totul pare ok despre modul in care se retin adresele metodelor virtuale (https://www.go4exper...le-vptr-t16544/). Insa..am un mic exemplu si 2 intrebari: class Base { public: virtual void function1() { cout << "Base :: function1()\n"; } virtual void function2() { cout << "Base :: function2()\n"; } virtual ~Base() { cout << "Base destructor" << endl; } Base() { cout << "Base constructor" << endl; } }; class D1 : public Base { public: ~D1() { cout << "Desturctor of D1" << endl; } D1() { cout << "Constructor of D1" << endl; } virtual void function1() { cout << "D1 :: function1()\n"; } }; class D2 : public D1 { public: ~D2() { cout << "Desturctor of D2" << endl; } D2() { cout << "Constructor of D2" << endl; } //virtual void function2() { cout << "D2 :: function2()\n"; } }; class D3 : public D2 { public: ~D3() { cout << "Desturctor of D3" << endl; } D3() { cout << "Constructor of D3" << endl; } virtual void function2() { cout << "D3 :: function2()\n"; } }; int main() { D3 *d = new D3; Base *b = d; d->function1(); d->function2(); delete (; return (0); } Interebari:
|
#2
Posted 15 January 2018 - 15:00
Am mai experimentat si am observat ca e suficient ca destructorul virtual sa fie de acelasi "rang" cu cel al clasei pe care lucrez...adica daca am ceva de genul acesta:
D3* d3 = new D3; D2* ptrd2 = d3; d3->function1(); delete ptrd2; Este suficient ca destructorul din D2 sa fie virtual (sters cel din clasa de baza) si functioneaza ok, sau daca il declar in D1 o sa functioneze cu toate subclasele acestuia (D2,D3). In exemplul de fata D1 este clasa de baza pentru D2, si al fel D2 este clasa de baza pentru D1? |
#3
Posted 15 January 2018 - 17:25
Mostenire, fara virtual => compilatorul genereaza direct apelul catre Base::foo() https://godbolt.org/g/3YkNJV
Mostenire, cu virtual => compilatorul genereaza cod care se uita prin virtual table https://godbolt.org/g/jqRRLV Edited by dani.user, 15 January 2018 - 17:25. |
#4
Posted 15 January 2018 - 17:31
Am mai aprofundat de cand am postat si (m-am trezit) si am vazut ca o data ce un destructor e declarat virtual in clasa de baza, toate clasele derivate vor avea destructorul virtual.
Ce nu prea inteleg e de unde stie pe care sa-l cheme si de ce trebuie sa fie virtuali? Si inca o mica nelamurire de care nu am reusit sa dau pe net...atunci cand se deriveaza clasa de baza iar clasa derivata mosteneste vPtr, in pointer raman datele din clasa de baza unde se adauga detaliile clasei derivate sau vPtr va contine detalii doar despre clasa in cauza ? Edited by virgil94, 15 January 2018 - 17:35. |
#5
Posted 15 January 2018 - 17:39
vPtr e un array de pointeri la functii (e adaugat automat ca un membru al clasei). In cazul clasei de baza, array-ul va tinti spre functii ale clasei de baza; in cazul celei derivate va tinti spre functii ale clasei derivate.
Un exemplu ce foloseste C: https://forum.softpe...-c-pur-windows/ |
#6
Posted 15 January 2018 - 17:49
dani.user, on 15 ianuarie 2018 - 17:39, said:
vPtr e un array de pointeri la functii (e adaugat automat ca un membru al clasei). In cazul clasei de baza, array-ul va tinti spre functii ale clasei de baza; in cazul celei derivate va tinti spre functii ale clasei derivate. Un exemplu ce foloseste C: https://forum.softpe...-c-pur-windows/ Da..dar din ce am citit referindu-ne la clasa derivata aceasta tine pointer la functie catre clasa de baza in cazul in care clasa derivata nu reimplementeaza metoda virtuala definita in clasa de baza. (https://www.go4exper...le-vptr-t16544/) Si tot baiatul ala de mai sus spunea va vptr e mostenit (dupa cum a "mazgalit" si pe schema) iar o data ce e mistenit ma gandeam ca e mostenit cu pointerii la functii pr care ii detine clasa de baza. |
#8
Posted 15 January 2018 - 18:12
Deja realitatea bate teoria.
Exemplul de la tine [color=#ff0000][b]vtable for Derived:[/b][/color] .quad 0 .quad typeinfo for Derived .quad Derived::foo() typeinfo for Derived: .quad vtable for __cxxabiv1::__si_class_type_info+16 .quad typeinfo name for Derived .quad typeinfo for Base typeinfo name for Derived: .string "7Derived" typeinfo for Base: .quad vtable for __cxxabiv1::__class_type_info+16 .quad typeinfo name for Base typeinfo name for Base: .string "4Base"Nu este nici un vtable pentru base class. |
#9
Posted 15 January 2018 - 18:18
Nu s-a mai obosit sa-l genereze ca nu era apelat foo din Base niciunde un acel cod.
Un exemplu mai sugestiv: https://godbolt.org/g/dhmwui |
#10
Posted 15 January 2018 - 18:29
Golanas si compilatorul asta ).
Deci din ce vad fiecare e cu vPtr al sau. Atunci de ce mai spunea ala ca se mosteneste? |
|
#11
Posted 16 January 2018 - 17:27
Mai am o mica problema.
#include <iostream> using namespace std; class a { public: virtual void test() {} }; class b { public: virtual void test2() {} }; class c : public a, public b { public: virtual void test33() {} }; int main() { a A; b B; c C; A.test(); B.test2(); C.test33(); cout << sizeof(c); return 0; } Daca ma uit cu explore compiler genereaza 3 tabele virtuale, dar in size-ul lui "c" regasesc doar 2, a lui a si b adica 8 bytes. De ce nu este luata in considerare si vptr pentru C in size-ul total? |
#12
Posted 16 January 2018 - 18:25
C contine 2 vptr (2*8 = 16 bytes) fiindca sunt doua "ramuri" de mostenire. N-are de ce sa includa 3 fiindca metodele ce le-ai adaugat lui C le poate usor adauga in continuarea uneia dintre ramuri (a ales A in cazul asta)
Daca faci un cast la pointeri, brusc observi ca se schimba valoarea pointerului ! #include <iostream> class A { public: virtual void test() {} }; class B { public: virtual void test2() {} }; class C : public A, public B { public: virtual void test33() {} }; int main() { A a; B b; C c; a.test(); b.test2(); c.test33(); std::cout << "C e la adresa " << &c << '\n'; std::cout << "C interpretat ca A ar fi la adresa " << static_cast<A*>(&c) << '\n'; std::cout << "C interpretat ca B ar fi la adresa " << static_cast<B*>(&c) << '\n'; std::cout << sizeof(c); return 0; } Quote
C e la adresa 0x23fe30 C interpretat ca A ar fi la adresa 0x23fe30 C interpretat ca B ar fi la adresa 0x23fe38 Prima parte din vptr-ul lui C poate fi interpretata ca si vptrul lui A, pe a 3-a pozitie gasind pointerul spre test(). |
#13
Posted 16 January 2018 - 20:36
Ok, hai sa te mai chinui putin si sa-ti spun ce am inteles eu despre vptr (poate mai ajuta pe cineva).
Base*ptrBase = new Dev;Destructorul din clasa de baza e virtual, deci automat si cel din clasa derivata. Inainte sa distruga obiectul Base compilatorul verifica toate tabelel virtuale in cautarea destructorului? Sau deja stie tipul obiectului si verifica direct in tabela acestuia? Iar daca nu ar fi virtuala, daca nu ar fi in tabela respectiva ce l-ar opri din a-l chema o data ce i-a identificat tipul? Ori destructorii, indiferent de numele lor (fie ~Base, fie ~Dev,) sunt vazuti ca si metode overloaded iar daca in clasa mea derivata nu este supraincarcat destructorul o sa-l cheme direct pe cel din clasa de baza sau urmatorul in ordina inversa creeari? |
#14
Posted 16 January 2018 - 21:39
Si destructorul virtual ajunge tot in virtual table: https://godbolt.org/g/beKxBa
Se vede ca, chiar fara sa declar destructorul lui C, compilatorul tot il genereaza, si are grija ca acesta sa cheme destructorii lui A si B. |
#15
Posted 17 January 2018 - 09:31
Mult mai clar, totusi mai am 2 mici intrebari ca sa-mi inchei ucenicia in vtabele.
[ https://image.ibb.co/cj8jGm/Capture.png - Pentru incarcare in pagina (embed) Click aici ] Code pentru imaginea de mai sus pentru cei interesati.
Spoiler
Deci daca sa zic ca sunt cea mai derivata clasa din ierarhia mea in cazul in care nu am supraincarcat o metoda virtuala ma duc si tin un pointer la functie din clasa mai de sus. Adica dupa ce o sa-mi termin treaba in vtable o sa am mapata toata ierarhia de clase astfel incat sa stiu ce functie pot invoca utilizand vtable din clasa mea derivata fara a mai avea nevoie de celelalte tabele. Deci daca am toate informatiile care imi trebuie in vtable al clasei mele de ce as mai vrea si vtable ale claselor mai mari decat mine in ierarhie (de ce sunt transmise vtable claselor derivate daca teoretic acestea nu le folosesc )? |
|
#16
Posted 20 January 2018 - 11:29
Vezi in standard care sunt cerintele pentru vtable. Fiecare compilator e liber sa le implementeze cum doreste.
Personal sunt mai interesat de cum pot evita mostenirea (pentru performanta sporita) decat de fiecare amanunt al implementarii sale. |
#17
Posted 23 January 2018 - 12:51
Da, nu stiu ce m-a lovit asa tare. Ma gandeam ca pentru a evita mostenira lui vptr e de ajuns final dar se pare ca nu e chiar asa. Am sa ma mai interesez. Mersi de hint.
|
Anunturi
▶ 0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users