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

C ++ частный и защищенный виртуальный метод а также Есть ли веская причина не использовать общедоступные виртуальные методы? говорим о не виртуальном интерфейсе (NVI) и непубличные виртуальные функции и их симбиоз. Скотт Мейерс также говорит в Effective C ++, что

Иногда виртуальная функция даже должна быть публичной, но тогда идиома NVI не может быть применена.

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

Например:

class Engine
{
public:
void SetState( int var, bool val );
{   SetStateBool( int var, bool val ); }

void SetState( int var, int val );
{   SetStateInt( int var, int val ); }
private:
virtual void SetStateBool(int var, bool val ) = 0;
virtual void SetStateInt(int var, int val ) = 0;
};

Каковы эффекты, если я положу SetStateBool а также SetStateInt в публичном разделе определения класса?

6

Решение

TLDRВы можете, но не должны.

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

class Engine
{
public:
void SetState( int var, bool val );
{
logToFile();
SetStateBool( int var, bool val );
}

void SetState( int var, int val );
{
logToFile();
SetStateInt( int var, int val );
}
private:
virtual void SetStateBool(int var, bool val ) = 0;
virtual void SetStateInt(int var, int val ) = 0;
void logToFile();
};

Поскольку открытый интерфейс не является виртуальным, все производные классы также автоматически регистрируются. Если бы вместо этого вы сделали SetStateBool а также SetStateInt public, вы не могли бы принудительное ведение журнала для всех производных классов.

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

2

Другие решения

Нет, в языке нет ничего, что мешало бы вам сделать функцию реализации public, В принципе, вы можете сделать что-то вроде:

class Base {
public:

virtual ~Base(){}

void work() { do_work(); }
virtual void do_work() = 0;

};

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

Например, вы можете пойти против идиомы RAII и сделать что-то вроде этого:

std::unique_ptr<MyClass,DoNothingDeleter> ptr ( new MyClass(...) );

где деструктор фактически не освободит память (и да, мне приходилось иметь дело с этим типом сценария раньше). Язык не запрещает этого, но в целом это плохая идея. Другими словами, только то, что это законно, не означает, что это морально (кредит Маршалла Клайна) … и это понятие идиомы.

0

По вопросам рекламы [email protected]