Недавно я решил использовать невиртуальную идиому интерфейса (NVI) для разработки интерфейса на C ++, главным образом с целью использования параметра со значением по умолчанию (таким образом избегая проблем, вызванных тем, что параметры по умолчанию статически связаны).
Я пришел с довольно тривиальным объявлением для моего класса, похожим на это:
class Interface{
public:
void func(Parameter p = 0);
virtual ~Interface();
private:
virtual void doFunc(Parameter p)=0;
};
void Interface::func(Parameter p){ doFunc(p); }
Interface::~Interface() {}
Я знаю, что предоставление тела функции в заголовке автоматически помечает функцию в качестве кандидата для встраивания (хотя я не знаю, предотвратит ли это определение вне класса). Я также знаю, что виртуальные функции не являются встроенными по очевидным причинам (мы не знаем, какая функция будет вызываться во время выполнения, поэтому мы не можем явно заменить вызовы телом функции).
Тогда, в этом случае, будет func()
быть отмеченным кандидатом на встраивание? Это не виртуальная функция, но все же звонки виртуальная функция. Это делает его встроенным?
Дополнительный вопрос: стоило ли это того? Тело состоит только из одного утверждения.
Обратите внимание, что этот вопрос скорее предназначен для того, чтобы узнать об этом, а не искать оптимизацию везде. Я знаю, что эта функция будет вызываться только несколько раз (ну, на данный момент, так что она может быть разумной в отношении того, как развивается программа), и что встраивание будет излишним, а не основной проблемой производительности моей программы.
Спасибо !
Я знаю, что предоставление тела функции в заголовке автоматически помечает функцию как кандидата для встраивания
Более менее; но вы делаете это, предоставляя тело функции в определении класса или явно объявив его inline
если это в шапке. В противном случае функция подчиняется правилу единого определения, и вы получите ошибки, если вы включите заголовок в несколько единиц перевода.
Обратите внимание, что это не заставляет компилятор встроить все вызовы функции; предоставление определения в заголовке просто позволяет встроить его в любой модуль перевода, который включает заголовок, если он считает, что оно того стоит. Кроме того, некоторые компиляторы могут выполнять «оптимизацию всей программы» и встроенные функции, даже если определение не доступно на сайте вызова.
Тогда, в этом случае, будет ли func () отмечен как кандидат для встраивания? Это не виртуальная функция, но все еще вызывает виртуальную функцию. Это делает его встроенным?
Да, все функции являются кандидатами на встраивание. Если они звонят сами, то, очевидно, вы не могли бы встроить все звонки; и если функция не известна во время компиляции (например, потому что она должна вызываться виртуально или через указатель функции). В этом случае вставка функции заменит прямой вызов func()
с виртуальным вызовом doFunc()
,
Обратите внимание, что иногда виртуальные вызовы могут быть встроенными, если динамический тип известен во время компиляции. Например:
struct MyImplementation : Interface {/*whatever*/};
MyImplementation thing;
thing.func(); // Known to be MyImplementation, func and doFunc can be inlined
Дополнительный вопрос: стоило ли это того?
Это зависит от того, что «это». Если вы имеете в виду время компиляции, то, пока функция остается короткой, вы можете получить некоторое преимущество (возможно, значительное, если функция вызывается много раз) за незначительные затраты. Если вы имеете в виду стоимость затрат времени, выбирая, где ее поставить, то, вероятно, нет; просто положите его там, где вам удобнее.
Других решений пока нет …