Новый способ реализовать делегаты с помощью C++ - Предпосылки
ОГЛАВЛЕНИЕ
Предпосылки
Различные виды классов
// kind_of_class.cpp
// Этот файл демонстрирует различные виды указателя на члены класса
class dummy_base1 { };
class dummy_base2 { };
class dummy_s : dummy_base1 { };
// Дойдя сюда, компилятор распознает dummy_s как
// вид "одиночного наследования".
typedef void (dummy_s::*pointer_to_dummy_s)(void);
size_t size_of_single = sizeof(pointer_to_dummy_s);
class dummy_m : dummy_base1, dummy_base2 { };
// Дойдя сюда, компилятор распознает dummy_s как
// вид "множественного наследования".
typedef void (dummy_m::*pointer_to_dummy_m)(void);
size_t size_of_multi = sizeof(pointer_to_dummy_m);
class dummy_v : virtual dummy_base1 { };
// Дойдя сюда, компилятор распознает dummy_s как
// вид "виртуального наследования".
typedef void (dummy_v::*pointer_to_dummy_v)(void);
size_t size_of_virtual = sizeof(pointer_to_dummy_v);
class dummy_u;
// опережающая ссылка, неизвестная в этот момент
typedef void (dummy_u::*pointer_to_dummy_u)(void);
size_t size_of_unknown = sizeof(pointer_to_dummy_u);
void main()
{
printf("%d\n%d\n%d\n%d", size_of_single, size_of_multi,
size_of_virtual, size_of_unknown);
}
Если вы компилируете и запускаете пример с помощью VC++, используя настройки проекта по умолчанию, вывод будет такой:
4
8
12
16
Вывод вышеприведенного примера не будет идентичным при компиляции с помощью других компиляторов C++. Дополнительную информацию смотрите в разделе статьи Дона, озаглавленном "Реализации указателей на функции-члены класса". Очевидно, что указатель на метод класса "unknown (неизвестный)" всегда имеет самый большой размер, за исключением компиляторов. Отныне мы будем разделять классы C++ на 2 категории:
- Известный класс (одиночный, множественный, Виртуальный)
- Неизвестный класс (предваряющее объявление)
Различные виды методов одного и того же класса
Ниже указаны несколько атрибутов (модификаторов), которые влияют на методы класса:
- Соглашение о вызовах: __cdecl, __stdcall, __fastcall, __thiscall. Обратитесь к статье «Передача параметров и соглашение об именах» за более подробной информацией. C++ позволяет, но игнорирует соглашения о вызовах для объявлений методов
- Число и типы аргументов
- Тип возвращаемого значения
- Постоянные методы против непостоянных
- Виртуальные методы против невиртуальных
К счастью, ни один из этих атрибутов (модификаторов) не влияет на размер указателя на метод. Предположим, что CKnownClass является известным классом, который уже был где-то описан; здесь приводится пример:
// __thiscall, непостоянный, 1 аргумент
typedef void (CKnownClass::*method_type_1)(int );
// __cdecl, непостоянный, 2 аргумента, возвращает CString
typedef CString (__cdecl CKnownClass:: method_type_2)(int, CString );
// __fastcall, постоянный, 3 аргумента, возвращает void*
typedef void* (__fastcall CKnownClass::* method_type_3)(
int, CString, void*) const;
void main()
{
printf("%d\n%d\n%d", sizeof(method_type_1),
sizeof(method_type_2),
sizeof(method_type_3));
}
Различные виды свободных функций или статических методов
Ниже указаны несколько атрибутов (модификаторов), которые влияют на свободные функции или статические методы:
- Соглашение о вызовах: __cdecl, __stdcall, __fastcall
- Число и тип аргументов
- Тип возвращаемого значения
Аналогично, атрибуты не влияют на размер указателей на свободные функции. Размер должен быть равен 4 байтам на всех 32-битных платформах и должен быть равен 8 на всех 64-битных платформах.