vtable - budowa, modyfikowanie

0

Kompilator: BCB 6 (x86)
Idea: modyfikacja wskaźnika do vtable - różna funckja wirtualna w zależności od konstruktora
Warunki: tylko jedna klasa bazowa (interfejs), brak destruktora wirtualnego, brak klas pochodnych

//Interfejs:
class Face
{
   virtual void Metoda() = 0;
   virtual void MetodaA() = 0;
   virtual void MetodaB() = 0;
   virtual void MetodaC() = 0;
};

//Klasa:
class Klasa
{
   struct { void *Dane1; void *Dane2; } Dane;
   virtual void Metoda() { /*implementacja*/ };
   virtual void MetodaA()  { /*implementacja*/ };
   virtual void MetodaB()  { /*implementacja*/ };
   virtual void MetodaC()  { /*implementacja*/ };
public:

   //konstruktory inkrementujące wskaźnik do vtable
   Klasa() {};
   Klasa(int param)   { *((void***)this) += 1; }; // - wywołując Metoda() wywołamy MetodaA()
   Klasa(char* param) { *((void***)this) += 2; }; //jw. MetodaB()
   Klasa(char param)  { *((void***)this) += 3; }; //jw. MetodaC()

   //wywołanie
   inline void operator() { Metoda(); };
};

//wywołanie
(Klasa('M'))(); //wywoła MetodaC()
(Klasa("xyz"))(); //wywoła MetodaB()

I teraz mam pare pytań odnośnie vtable. W zasadzie interesuje mnie tylko BCB, ale pytania również tyczą sie innych kompilatorów (niestety standart c++ nie określa tego o co pytam).

  1. Czy wskaźnik do vtable zawsze będzie na początku klasy (przypominam - dziedziczenie pojedyncze) ?
  2. Czy taki interfejs jak wyżej gwarantuje, że vtable składać się bedzie z dokładnie z czterech wskaźników w takiej kolejności jak podano ?
  3. Czy wskaźniki w vtable będą rozmiaru wskażnika void* ?
  4. Czy mimo wszystko w vtable nie znajdzie się destruktor wirtualny ?
  5. Jakie inne zagrożenia wynikają z takiej konstrukcji ?

Dodam, że oczywiście można to zaimplementować przy pomocy dodatkowego wskażnika na funkcje składową i operowanie na nim zamiast na funkcjach wirtualnych, jednak ja chce po swojemu :) Chce aby rozmiar klasy mieścił się w 16 bajtach:
Dane (8 bajtów) + wskaźnik do vtable(4 bajty) = 12 bajtów
Dane (8 bajów) + wskaźnik na funkcje (4-16 bajtów) = 12-24 bajty
Domyślnie w bcb wskaźnik na funkcje składową ma 12 bajtów co daje razem 20, różnie to bywa w zal. od kompilatora i opcji kompilacji

0
  1. Na ogół jest.
  2. Tak.
  3. Tak.
  4. Póki co, dtor nie jest domyślnie wirtualny. Zresztą, jeżeli dziedziczysz interface z klasy abstrakcyjnej, to nie robi to większej różnicy ;)
  5. Dość ryzykowna konstrukcja. Nie polecam.
   Klasa(int param)   { *((void***)this) += 1; }; // - wywołując Metoda() wywołamy MetodaA()
   Klasa(char* param) { *((void***)this) += 2; }; //jw. MetodaB()
   Klasa(char param)  { *((void***)this) += 3; }; //jw. MetodaC()

Zamiast inkrementować wartości, przypisuj np: vtable[0]=vtable[1] itd.

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