Учитывая следующий пример:
class A
{
protected:
static void useful_function_without_side_effects() {...}
}
class B : private A
{
// B has no friends :(
public:
void travel_back_in_time() { super_useful_function(); }
}
Вопрос 1: Будет ли разрешено компилятору оптимизировать базовый класс A, поскольку этот базовый класс не может реально влиять на B или на поведение во время выполнения каким-либо образом?
Вопрос 2: Изменится ли это, если наследование будет объявлено частным виртуальным, как это?
class B : private virtual A
Неполиморфные классы вообще не имеют никаких представителей во время выполнения. Единственные вещи, которые могут существовать, это объекты и методы, которые рассматриваются как функции. Класс только инструктирует компилятор получить доступ к частям объекта и разрешить вызов метода в соответствии с определением. После непосредственного разрешения все жестко закодировано в коде времени выполнения. private
квалификатор здесь ничего не меняет.
Класс A (не имеющий полей), полученный из B, не «добавляет размер» к объекту класса B, если это ваш вопрос. Это всегда верно, если у класса A нет полей, но sizeof (A) всегда будет по крайней мере 1. Хотя также нет такого правила, что размер B должен быть суммой размеров всех полей и базовых классов.
Это добавляет размер к классу B. Стандарт не уточняет, каким образом. В типичных реализациях он всегда будет увеличивать размер класса B на размер одного указателя плюс любой возможный размер класса A.
Обычно виртуальное наследование реализуется с использованием «указателя на себя». Таким образом, подобъект производного класса (A) физически является частью общего объекта, но к нему никогда не осуществляется прямой доступ, только через указатель на весь объект.
Это более-менее ситуация, когда у вас есть поля A и B без полей с полями общего размера 4:
Физическое наследство:
B: [A: 0] [B extension: 4]
Виртуальное наследование:
B: [A virtual: <pointer size>] [B extension: 4] [A shared subobject: 1]
Порядок этих вещей может отличаться в разных реализациях, хотя это часть определения ABI, а не частное правило компилятора (то есть все компиляторы на одной платформе должны использовать одни и те же правила).