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).
- Czy wskaźnik do vtable zawsze będzie na początku klasy (przypominam - dziedziczenie pojedyncze) ?
- 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 ?
- Czy wskaźniki w vtable będą rozmiaru wskażnika void* ?
- Czy mimo wszystko w vtable nie znajdzie się destruktor wirtualny ?
- 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