Можно ли расширить виртуальный интерфейс без перекомпиляции клиентского кода? - PullRequest
8 голосов
/ 19 апреля 2011

Библиотека предоставляет класс с виртуальными функциями.Можно ли расширить этот класс новыми виртуальными функциями без перекомпиляции двоичных файлов, динамически связанных с библиотекой?

Я считаю, что в стандарте это невозможно.Существуют ли платформы, допускающие это?

Было бы проще, если бы новые функции добавлялись только в конец тела класса?

1 Ответ

5 голосов
/ 19 апреля 2011

Стандарт не касается двоичной совместимости. Хотя это касается классов, и, «изменяя» определение класса с одного модуля перевода на другой, вы действительно вызываете неопределенное поведение.

Большинство компиляторов допускают ряд изменений без необходимости перекомпиляции, однако список невелик ... и для этого я бы сказал, что это невозможно, в зависимости от априорных знаний о производные классы .

Проблема, которую я предвижу, заключается в оптимизации, которую компиляторы обычно выполняют для виртуальных таблиц.

Когда вы создаете класс с виртуальными функциями, вы получаете виртуальную таблицу, которая выглядит так:

// B virtual table
0 - Offset to complete object
1 - RTTI
2 - func0
3 - func1
...

Чтобы получить некоторое пространство, собственные виртуальные функции производного класса обычно «добавляются»:

// D virtual table
Same as B
N+3 - func(N+1)
N+4 - func(N+2)

Таким образом, у объекта D есть только один виртуальный указатель, который можно использовать как таковой, даже если тип является (статически) a B (через указатель или ссылку).

Однако, если бы вы расширили B без перекомпиляции D, то это было бы просто крахом, поскольку при вызове функции N+1 для B вы бы вместо этого вызвали функцию N+1 для D который, вероятно, даже не имел бы таких же аргументов ... ау!

Однако это можно сделать, если вы знаете , тогда ни один производный класс не добавит ни одной своей виртуальной функции.

...