перекомпилировать после изменения базового класса

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

Это утверждение взято из книги Страуструпа. Итак, если базовый класс находится в файле .so, и мы просто меняем реализацию функции-члена, значит ли это, что нам не нужно перекомпилировать мою программу, связанную с этим общим объектом?


person PnotNP    schedule 08.02.2012    source источник


Ответы (3)


Формально, если вы не перекомпилируете, вы нарушаете правило одного определения и получаете неопределенное поведение.

На практике, пока изменяемая вами функция-член нигде не встроена и вы не меняете сигнатуру, вы, вероятно, сохраняете двоичную совместимость. На большинстве платформ. Если вам повезет, документация вашей платформы предоставляет такую ​​гарантию.

person Ben Voigt    schedule 08.02.2012
comment
Из вопроса неясно, находится ли реализация функции в заголовке как встроенное определение или в отдельном исходном файле, который пользователи класса видят только в форме объекта. Если первое, предположим, что оно встроено. Если второе, то скорее всего не будет. - person ; 08.02.2012

Я считаю, что ваше понимание правильное. Простое изменение тела функции-члена не меняет объема пространства, необходимого для экземпляра этого объекта. Код не хранится «в» экземпляре объекта; только данные есть.

Когда класс компилируется, ссылки на поля данных членов являются просто смещениями от начала данных этого объекта. А данные производных классов обычно размещаются после данных базового класса. Таким образом, если вы добавите поле в базовый класс, все правильные смещения для данных производного класса будут изменены, что означает, что базовый класс необходимо перекомпилировать, чтобы он указывал на новые (правильные) смещения.

До

class Foo {
    int a;              // offset 0 (assuming no vtable)
}

class Bar : public Foo {
    int b;              // offset 4
}

Bar bar;  bar.b = 7;    // sets the 32-bit value at this+4 to 7

После

class Foo {
    int a;              // offset 0
    int c;              // offset 4
}

class Bar : public Foo {
    int b;              // offset 8
}

Bar b;   bar.b = 7;     // Without recompiling: sets the 32-bit value at this+4
                        //   which is actually where Foo.a is stored!
                        // With recompiling: sets the 32-bit value at this+8
person Jonathon Reinhart    schedule 08.02.2012

Если это просто реализация, она должна работать нормально. Это вся концепция Windows DLL. Добавление или удаление интерфейсов не изменит размер класса (если только вы не введете новую виртуальную функцию), но в целом способ, которым функции, размещенные в памяти, может быть изменен. Поэтому требуется перекомпиляция, если вы используете новую функцию. С другой стороны, большинство современных компиляторов достаточно умны, чтобы идентифицировать соответствующие изменения из-за простой модификации файлов заголовков.

person sarat    schedule 08.02.2012
comment
С другой стороны, большинство современных компиляторов достаточно умны, чтобы идентифицировать соответствующие изменения из-за простой модификации файлов заголовков. Не могли бы вы уточнить? Для C++ я еще не видел компилятора, который проверяет, как изменились заголовочные файлы. В лучшем случае после интеграции с системой сборки проверяют, не изменился ли вообще заголовочный файл. - person ; 08.02.2012
comment
Это не во всех случаях, хотя при компиляции я видел, как компиляторы Microsoft сообщают об отсутствии изменений в окне вывода. - person sarat; 08.02.2012
comment
Нет, библиотеки DLL Windows не имеют ничего общего с классами или наследованием C++. - person Ben Voigt; 08.02.2012