Во-первых, вызов метода через нулевой указатель или ссылку строго говоря неопределенное поведение. Но это может произойти, если вызов не является виртуальным.
Вызов виртуальных методов виртуально (через указатель / ссылку, а не из производного класса с способом вызова Class :: Method ()) всегда завершается ошибкой, если ссылка / указатель имеет значение null, поскольку виртуальные вызовы требуют доступа к vtable и доступа к vtable через нулевой указатель / ссылку невозможно. Таким образом, вы не можете вызвать пустой виртуальный метод через ссылку / указатель.
Чтобы понять это, вам нужно больше узнать о том, как организован код. Для каждого не встроенного метода есть сегмент сегмента кода, содержащий машинный код, реализующий метод.
Когда вызов выполняется не виртуально (из производного класса или не виртуального метода через ссылку / указатель), компилятор точно знает, какой метод вызывать (без полиморфизма). Поэтому он просто вставляет вызов в точную часть кода и передает указатель this в качестве первого параметра. В случае вызова через нулевой указатель этот также будет нулевым, но вам все равно, если ваш метод пуст.
Когда вызов выполняется виртуально (через ссылку / указатель), компилятор не знает, какой именно метод вызывать, он только знает, что есть таблица виртуальных методов и адрес таблицы хранится в объекте. Чтобы определить, какой метод вызывать, необходимо сначала разыменовать указатель / ссылку, добраться до таблицы, получить из нее адрес метода и только потом вызывать метод. Чтение таблицы выполняется во время выполнения, а не во время компиляции. Если указатель / ссылка нулевые, вы получаете ошибку сегментации в этой точке.
Это также объясняет, почему виртуальные вызовы не могут быть встроены. Компилятор просто не знает, какой код встроить, когда просматривает исходный код во время компиляции.