2015-10-09 4 views
4

Я считаю довольно странным, что неиспользуемые виртуальные функции должны быть определены в отличие от неиспользуемых обычных функций. Я немного понимаю неявные vtables и vpointers, которые создаются при создании объекта класса - это несколько отвечает на вопрос (что функция должна быть определена так, чтобы указатели на виртуальную функцию могли быть определены), но это толкает мой запрос еще дальше.Зачем нужны неиспользуемые виртуальные функции?

Зачем нужна запись vtable для функции, если нет абсолютно никакой вероятности, что виртуальная функция будет вызвана вообще?

class A{ 
    virtual bool test() const; 
}; 

int main(){ 
    A a; //error: undefined reference to 'vtable for A' 
} 

Даже если я объявил A::test() она никогда не использовалась в программе, но она по-прежнему бросает ошибку. Может ли компилятор не запускаться через программу и реализовать test() никогда не назывался - и, следовательно, не требуется запись vtable? Или это неразумно ожидать от компилятора?

+0

Вы не можете создать виртуальный класс. Но тривиально создать нулевую функцию или функцию, которая просто возвращает константу объявленного типа. – Logicrat

ответ

5

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

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

+0

Я бы даже сказал, что это невозможно решить. Скажем, у вас есть библиотека, которую вы открываете с помощью 'dlopen', которая дает вам указатель на класс с неопределенной виртуальной функцией. Компилятор не может это поймать, поэтому это будет ошибка времени выполнения ... – Florian

3

ОП говорит, что он уже знает о vtables и vpointers, поэтому он понимает, что существует разница между неиспользуемыми виртуальными функциями и неиспользуемыми не виртуальными функциями: неиспользуемая не виртуальная функция нигде не упоминается, а виртуальная функция ссылается хотя бы один раз в vtable своего класса. Таким образом, по существу, возникает вопрос, почему компилятор недостаточно умен, чтобы воздержаться от размещения ссылки на виртуальную функцию в таблице vtable, если эта функция нигде не используется. Это позволит функции также оставаться неопределенными.

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

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

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

Итак, просто определите пустую виртуальную функцию, которая содержит ASSERT(FALSE) и продолжите свою жизнь.

+0

@AlexD хорошо, OP говорит, что он уже знает о vtables и vpointers, поэтому я не чувствовал, что мне нужно решить эту проблему. Но вы правы, лучше всего говорить о вещах, чем оставлять вещи подразумеваемыми. Поэтому я поправил свой ответ. –

+0

«Компилятор обычно видит только один .cpp-файл за раз, поэтому он не знает, есть ли у вас какой-то исходный файл, который вызывает эту функцию». Если бы у меня был исходный файл, который вызывал эту функцию, не мог ли в этом исходном файле заголовок, включенный для этого класса, который не имеет виртуального определения? Как я могу вызвать функцию-член, не указав класс в исходном файле? – AntiElephant

+0

@AntiElephant существует [разница между декларацией и определением] (http://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration). заголовочный файл будет содержать *** описание *** функции, что делает его законным для любой части кода, чтобы поместить вызов этой функции. Но *** определение *** функции - это то, где вы предоставляете фактическое тело функции, и обычно это делается в одном файле .cpp. –

0

Весь смысл виртуальных функций заключается в том, что их можно вызвать с помощью указателя базового класса. Если вы никогда не используете виртуальную функцию базового класса, то почему вы ее определили? Если он используется, вам нужно либо оставить родительскую реализацию (если она не является чистой виртуальной), либо определить вашу собственную реализацию, так что код, использующий ваши объекты через базовый класс, может действительно использовать его.В этом случае используется функция , она просто не используется напрямую.

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