2016-03-03 4 views
2

Я пытался понять, почему я могу создать чистую виртуальную функцию в файле заголовка, который не был реализован в используемой библиотеке, и что это не будет вызывают связь или даже отказ во время выполнения. Вышеуказанное может быть немного неточным, но вот какой-то код для его резервного копирования.Общая библиотека C++: чистая виртуальная функция не вызывает ошибку связи

Вот определение интерфейса:

class A 
{ 
public: 
    static A* Create(); 

    virtual ~A() {} 

    virtual status_t start() = 0; 
    virtual status_t stop() = 0; 
}; 

У меня есть C++ разделяемую библиотеку, которая содержит реализацию "AImpl" + The A :: Create() функцию (см):

A* A::Create {return new AImpl;} 

class AImpl : public A 
{ 
public: 
    A() {} 
    virtual ~A() {} 

    virtual status_t start() {} 
    virtual status_t stop() {} 
}; 

Я создаю общую библиотеку - проблем нет. Теперь я добавляю еще одну чистую виртуальную функцию в файле заголовка для класса А:

class A 
    { 
    public: 
     static A* Create(); 

     virtual ~A() {} 

     virtual status_t start() = 0; 
     virtual status_t stop() = 0; 
     virtual status_t write() = 0; 
    }; 

создать тест приложение, которое использует его:

void main() 
{ 
    A* a = A::Create(); 
    a->start(); 
    a->stop(); 
    a->write(); 
} 

Теперь я понимаю, что вышеуказанная компилирует, но я бы подумайте, что это не сработает, поскольку для вызова write() в общей библиотеке нет реализации. Даже во время выполнения не происходит ни крушения, ни чего-либо. Кажется, что вызов записи пропущен. Может кто-нибудь объяснить - это было бы весьма признателен :-)

Благодарности - И извините за длительный вопрос, это было немного трудно для меня, чтобы объяснить точный вопрос в «одном лайнере» ..

+1

Вы действительно уверены, что он перекомпилирован после изменения кода? Можете ли вы заставить перестроить? – leemes

+0

Да, я уверен, что он скомпилирован. Но, как я вижу, компилятор не должен жаловаться. Код в порядке. Но реализация отсутствует в lib, поэтому я бы догадался об ошибке ссылки. –

+0

Вы также перекомпилировали библиотеку? Я думаю, компиляция должна завершиться неудачей в 'A :: create', так как' AImpl' является абстрактным. – leemes

ответ

0

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

+0

Спасибо. Да, это, кажется, общий вывод. Компилятор/компоновщик не поможет мне в ситуации, когда я свяжусь со старой библиотекой, когда дело доходит до чистых виртуальных функций. Удивительно для меня - но мне придется иметь дело с этим :-) –

0

Чистые виртуальные функции никогда не приведут к сбоям во время связывания. Вместо этого, чистые виртуальные функции вызовут ошибку компиляции, если вы попытаетесь навязать объект абстрактного типа.

Reminer - абстрактный тип - это тип, который имеет (прямо или косвенно через наследование) хотя бы одну чистую виртуальную функцию, которая не была переопределена.

+0

Спасибо за быстрый ответ. Вы хотите сказать, что, как ожидается, вышеупомянутое не вызывает никаких ошибок, когда я связываюсь с библиотекой, использующей старую версию A? –

0

Это может скомпилировать или построить, если решение было ранее построено. Это означает, что он использует старый объектный код. Попробуйте сделать чистую сборку своего решения, а затем перестройте его. Как только ваше решение будет очищено. Затем попытайтесь скомпилировать унаследованный класс. Еще одна вещь, которая может вызывать беспокойство, заключается в том, что вы объявили свой унаследованный класс следующим:

класс AImpl: A {...};

Мой вопрос о том, как AImpl унаследован от A? Намерены ли вы public, protected или private наследование?

EDIT

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

+0

Спасибо. Вы правы, что настоящий код имеет публичное наследование. Я обновляю сообщение, чтобы показать это. Я знаю, что повторная компиляция разделяемой библиотеки (которая имеет реализацию) вызовет ошибку компиляции. Но я был удивлен, что я могу добавить новые чистые виртуальные методы в заголовочный файл, не получая никакой компиляции/ссылки на ошибку в приложении, используя общую библиотеку lib. Даже во время выполнения я не получаю ошибок - кажется, просто пропустить звонок? –

+0

@ user6014883 Я отредактировал свой ответ, добавив новый раздел, объясняющий, что происходит с привязкой к библиотекам. –

+0

Да, спасибо за комментарии. Я понимаю из комментариев, что, действительно, я не должен ожидать ошибки компиляции/ссылки со старой библиотекой. Это было немного удивительно для меня. Но я просто буду иметь дело с этим :-) –

Смежные вопросы