Проблема с вызовом функции , когда она находится в .lib

StackOverflow https://stackoverflow.com/questions/622210

  •  05-07-2019
  •  | 
  •  

Вопрос

У меня есть класс со статическим методом, который выглядит примерно так:

class X {
    static float getFloat(MyBase& obj) {
        return obj.value();  // MyBase::value() is virtual
    }
};

Я вызываю это с помощью экземпляра MyDerived, который является подклассом MyBase:

MyDerived d;
float f = X::getFloat(d);

Если я свяжу obj-файл, содержащий X, с моим исполняемым файлом, все будет работать так, как ожидалось.Если я ожидаю получить 3,14, я это получу.

Если я создам .библиотеку, содержащую X.obj-файл и ссылку в .lib, она сломается.Когда я вызываю getFloat(), он возвращает -1.#IND00.Это какой-то тип сторожевого значения, которое должно подсказать мне, что здесь не так?

Отличается ли что-нибудь, когда вы ссылаетесь в lib, а не на obj напрямую?

Я не получаю никаких предупреждений компилятора или ошибок.

Редактировать:
Я использую Visual Studio 2005 в Windows XP Pro SP3.Чтобы убедиться, что я не связывал старые файлы, я клонировал метод value() в новый метод value2() и вызвал его вместо этого.Поведение было таким же.

Правка № 2:
Итак, если я отслеживаю вызов с помощью моего отладчика, я обнаруживаю, что он вообще не входит в мой метод value().Вместо этого он переходит к другому (несвязанному) методу.Это заставляет меня думать, что моя виртуальная таблица повреждена.Я думаю, что поведение, которое я наблюдаю, должно быть побочным эффектом какой-то другой проблемы.


Решено! (спасибо Владу)
Оказывается, я нарушал правило единого определения (ODR), хотя это не было очевидно из кода, который я опубликовал. Это это отличная статья от ребят из Visual C ++, которая объясняет проблему и один из способов ее устранения.В /D1репортсинглекласс - описание флаг компилятора - это фантастический инструмент обучения.

Когда я выгрузил макет моего класса для MyBase и MyDerived в двух разных проектах, я обнаружил различия между вызывающим кодом и кодом библиотеки.Оказывается, у меня было немного #ifdef блоки в моих заголовочных файлах и соответствующие #определить оператор был в предварительно скомпилированном заголовке для основного проекта, но не в подпроекте (библиотеке).Я упоминал, какими злыми, по моему мнению, являются макросы препроцессора?

В любом случае, я публикую этот материал только потому, что это может быть полезно кому-то другому. Этот вопрос был также очень полезен для меня.

Это было полезно?

Решение

Эта проблема возникнет, когда библиотека и исполняемый файл будут скомпилированы с различные определения MyDerived класс (т.е.различные версии .h/.hh/.hpp файл, который объявляет MyDerived.Полностью очистите и перестройте ваши проекты.За исключением этого, различные параметры компилятора мог бы будьте ответственны, хотя это несколько маловероятно.

Если проблема не устраняется после восстановления всего с нуля, устраните ее, создав экземпляр манекена MyDerived объект внутри getFloat, в библиотеке.Используйте отладчик для сравнения vtable о манекене MyDerived (созданный в библиотеке) и vtable из числа MyDerived ссылка на объект, переданная в качестве параметра (создается в исполняемом файле.) Что-то должно сразу броситься в глаза.

Другие советы

Поскольку библиотека - это просто контейнер, если вы связываете один и тот же obj-файл в обоих случаях, то, как говорит Брайан, они не должны (не могут?) быть различиями.

Одна вещь, на которую следует обратить внимание, - это то, что если вы изменили определение MyBase, вам, очевидно, нужно перекомпилировать как библиотеку, так и код, использующий ее.Например, если вы добавили новый виртуальный метод в MyBase перед методом value, то это привело бы к сбою в библиотеке, поскольку смещение значения в v-таблице было бы другим.

Не должно быть никакой разницы.Просто убедитесь, что файлы .h, которые вы включаете, точно соответствуют .библиотеке, на которую вы ссылаетесь.Я подозреваю, что вы, возможно, ссылаетесь на старый .lib-файл.

Если вы используете visual Studio, вместо явного указания .файл библиотеки просто щелкните правой кнопкой мыши на проекте и установите зависимости для проекта .lib.Таким образом, вы будете уверены, что он использует правильный файл .lib.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top