Вы не вызываете чисто виртуальную функцию, вы выполняете поиск в виртуальной таблице текущей записи в таблице виртуальных функций для этой функции.
Как это происходит, в этот момент эточисто виртуальная функция, поэтому вы зависаете из-за UB.
В первом случае вы получаете ошибку компоновщика, потому что gcc вызывает девиализацию вызова на fun
в ctor.Девиртуализированный вызов fun
напрямую вызывает чисто виртуальный метод.Это возможно, потому что при построении Interface
компилятору известно состояние таблицы виртуальных функций (модификации производного класса к ней еще не происходят).
Во втором случае компилятор может девиртуализировать вызовcallFun
из ctor.Но вызов fun
изнутри callFun
не может быть девиртуализирован, поскольку callFun
может быть вызван извне ctor в другом методе.Девиртуализация была бы неправильной в общем случае .
В этом конкретном случае, если компилятор девиртуализировал callFun
, а затем встроил его, он мог бы затем девиртуализировать fun
в подписанной копии.Но компилятор этого не делает, так что никакой девиртуализации не происходит.
Кроме того, вы можете реализовать эту чисто виртуальную функцию и заставить каждый предоставленный вами пример и ссылаться, и нормально работать.
void Interface::fun() const {}
в любом месте любого .cpp
файла, на который есть ссылка, создаст ссылку на ваш код и будет верным в любом случае.Чистый виртуальный не означает «не имеет реализации» в C ++, он просто означает «производный класс должен обеспечивать переопределение, и для меня законно не иметь реализацию».