Собственно, главный вопрос в том, почему содержимое указателей на виртуальный метод, возвращающий пользовательский класс отличается от других указателей на вируальные методы?
class Bar{
};
struct Baz {
int a;
int b;
int c;
};
class Foo {
public:
virtual void VirtualVoid(){}
virtual int VirtualInt(){}
virtual char* VirtualCharPtr(){}
virtual double PureVirtualDouble() = 0;
virtual Bar VirtualEmptyClass() {}
virtual Baz VirtualNotEmptyClass(){}
virtual long long PureVirtualLongLong() = 0;
};
Отладчик:
foo_ptr_0: void (Foo::*)() :0018FF48 __thunk__ [B,0,1,0]{0,0}
foo_ptr_1: int (Foo::*)() :0018FF3C __thunk__ [B,0,5,0]{4,0}
foo_ptr_2: char* (Foo::*)() :0018FF30 __thunk__ [B,0,9,0]{8,0}
foo_ptr_3: double (Foo::*)() :0018FF24 __thunk__ [B,0,D,0]{12,0}
foo_ptr_4: Bar (Foo::*)() :0018FF18 __thunk__ [B,0,11,4]{16,0}
foo_ptr_5: Baz (Foo::*)() :0018FF0C __thunk__ [B,0,15,4]{20,0}
foo_ptr_6: long long (Foo::*)() :0018FF00 __thunk__ [B,0,19,0]{24,0}
компилятор, флаги все стандартные;
bcc32 --version
Embarcadero C++ 6.60 for Win32 Copyright (c) 1993-2013 Embarcadero Technologies, Inc.
Revision 6.60.4846.33249
Из того, что откопал:
Первое поле, которое у всех "B" - это, похоже, индекс соглашения о вызове.
При компиляции с разными флагами для указателя foo_ptr_4:
Pascal (__pascal) (-p)
foo_ptr_4 __thunk__ [C,0,11,0]{16,0}
C (__cdecl) (-pc)
foo_ptr_4 __thunk__ [B,0,11,4]{16,0}
_msfastcall (__msfastcall) (-pm)
foo_ptr_4 __thunk__ [I,0,11,4]{16,0}
Fastcall(register) (__fastcall) (-pr)
foo_ptr_4 __thunk__ [D,0,11,0]{16,0}
stdcall (__stdcall) (-ps)
foo_ptr_4 __thunk__ [F,0,11,4]{16,0}
Отсюда видно что четвертое поле нулевое при __pascal и __stdcall вызове.
Третье поле, наверное, смещенение от начала объекта на указатель функции:
Borland compilers add an offset of 1 to data member pointers in order to distinguish a
pointer to the first data member from a NULL pointer, represented by 0. The other compilers
have no offset, but represent a NULL data member pointer by the value -1.