Преимущества NVI в C++ (non virtual interface)
От: minorlogic Украина  
Дата: 29.04.06 09:45
Оценка:
Речь идет о
http://www.ddj.com/dept/cpp/184403760
http://www.gotw.ca/publications/mill18.htm

По работе столкнулся с NVI и возникли вопросы.

1. Неубедительная мотивация для использование NVI.

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

Добавлю, что абстрактные интерфейсы вводились в C++ именно с целью , заменить PIMPL и другие самопалки.

a. Мотивация при использовании классов , которые предполагают наследование от них
b. Мотивация при использовании классов , которые НЕ предполагают наследование от них.
Уверен , что такая мотивация есть , не высасывал же Сатер это все из пальца ....

2. Укажите преимущества перед абстрактными интерфейсами ( имеются ввиду абстрактные виртуальные функции).
И укажите преимущества перед PIMPL (без виртуальности).

3. Особенно интересует этот момент из контекста...
"And you would never make the virtual function public. All public functions would be non-virtual."

Т.е. рекомендация которая ЯВНО и насквозь противоречит архитектуре самого языка C++ , смотреть Страуструпа.

Готов к конструктивной критике , в надежде на то , что разберусь в вопросе.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Преимущества NVI в C++ (non virtual interface)
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 29.04.06 10:34
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Неубедительная мотивация для использование NVI.

M>Читал Herb Sutter но не проникся , вот хочу узнать у того кто проникся , чем обосновано усложнение класса, оверхед на двойную диспечирезацию и т.п по сравнению с абстрактными интерфейсами .

У меня мотивация для использования NVI прежде всего в явном разделение интерфейса (статичного) и реализации (специфичной для каждого класса полиморфной иерархии). Полезность этого разделения особенно проявляется, когда действие, которое мы хотим совершить над объектом, предполагает последовательность нескольких более мелких действий, специфичных для каждого объекта полиморфной иерархии. Отдавать эти мелкие действия на откуп пользователю класса чревато усложнением использования этого класса и ошибками.
-- Андрей
Re: Преимущества NVI в C++ (non virtual interface)
От: srggal Украина  
Дата: 29.04.06 10:35
Оценка:
Здравствуйте, minorlogic, Вы писали:


M>3. Особенно интересует этот момент из контекста...

M>"And you would never make the virtual function public. All public functions would be non-virtual."

Все нижесказанное есть ИМХО.

На NVI следует смотреть со стороны паттерна Шаблонные метод. Т.е. виртуальная функция реализует какую-то функциональность.

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

При использовании NVI ни потомки, ни тем более клиенты класса не смог самостоятельно вызвать функцию. Т.е. сам базовый класс определяеи момент вызова и его контекст, так сказать "жестко" закреплённое архитектурное решение.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Преимущества NVI в C++ (non virtual interface)
От: alexeiz  
Дата: 29.04.06 10:51
Оценка: 7 (2) +1
Здравствуйте, minorlogic, Вы писали:

M>http://www.gotw.ca/publications/mill18.htm

...
M>Готов к конструктивной критике , в надежде на то , что разберусь в вопросе.

Ты невнимательно читал статью. Многие из твоих вопросов не имеют смысла. Причём здесь pimpl? При чём здесь противоречие архитектуре языка? Здесь концептуальная проблема. Открытые виртуальные функции играют сразу две роли: интерфейса и модификации поведения через наследуемые классы. Саттер очень ясно её описывает:

// Example 1: A traditional base class.
//
class Widget
{
public:
// Each of these functions might optionally be
// pure virtual, and if so might or might not have
// an implementation in Widget; see Item 27 in [1].
//
virtual int Process( Gadget& );
virtual bool IsDone();
// ...
};

The problem is that "simultaneously" part, because each virtual function is doing two jobs: It's specifying interface because it's public and therefore directly part of the interface Widget presents to the rest of the world; and it's specifying implementation detail, namely the internally customizable behavior, because it's virtual and therefore provides a hook for derived classes to replace the base implementation of that function (if any). That a public virtual function inherently has two significantly different jobs is a sign that it's not separating concerns well and that we should consider a different approach.


Закрытие виртуальных методов позволяет убрать одну из ролей. Такие виртуальные методы уже не часть открытого интерфейса. Роль интерфейса играют невиртуальные методы. В этом и заключается смысл идиомы Non-Virtual Interface.

>Т.е. рекомендация которая ЯВНО и насквозь противоречит архитектуре самого языка C++ , смотреть Страуструпа.


Тут ты загнул. Страуструп здесь не причем.

Ты преподносишь NVI как что-то новое, до сих пор невиданное и не особо нужное. Эта идиома широко применялась задолго до того, как Саттер начал её популизировать. Смотри стандартную библиотеку. IOStreams библиотека — это год 1995 от силы. basic_stream_buffer. Открытый интерфейс не виртуален. Модификация поведения производится через виртуальные защищённые методы. И так везде в стандартной библиотеке. Поищи хотя бы функции начинающиеся с do_ — они все защищённые виртуальные.
Re[2]: Преимущества NVI в C++ (non virtual interface)
От: srggal Украина  
Дата: 29.04.06 11:11
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Модификация поведения производится через виртуальные защищённые методы. И так везде в стандартной библиотеке. Поищи хотя бы функции начинающиеся с do_ — они все защищённые виртуальные.


В виде прииркм NVI подразумевает private а не protected, а в целом +1
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Преимущества NVI в C++ (non virtual interface)
От: IROV..  
Дата: 29.04.06 13:16
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>1. Неубедительная мотивация для использование NVI.


Для меня убедительная..

сравним.

это:
class A
{
    virtual void Foo()
    {
        if(enable ==  false)
        { 
            Log << "Blah-Blah" << endl;
        }

        //TODO:

    }
};

class B
    : public A
{
    void Foo()
    {
        if(enable ==  false)
        { 
            Log << "Blah-Blah" << endl;
        }

        //TODO:
    }
};

с вот этим:
class A
{
    void Foo()
    {
        if( enable ==  false)
        { 
            Log << "Blah-Blah" << endl;
        }

        _Foo();
    }

    virtual void _Foo()
    {
        //TODO:
    }
};

class B
    : public A
{
    void _Foo()
    {
        //TODO:
    }
};






+ Возможность создания префикса и постфикса к функции
+ Легко менять(сопровождать) префикс/постфикса при этом не боясь забыть гдето поменять.
+ Меньше кода! а значит меньше проблем на сопровождение.
+ Помогает избежать ошибок (забытые юзером проверки), если нужна обязательная валидация.

— Ущемляет права юзера на ликведацию пре/пост-фикса (может это и к лучему)

P.S. знаю _Foo писать не безопастно (чертов STL ).. просто для наглядности
я не волшебник, я только учусь!
Re[2]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 17:43
Оценка:
Здравствуйте, Андрей Коростелев, Вы писали:

АК>Здравствуйте, minorlogic, Вы писали:


M>>Неубедительная мотивация для использование NVI.

M>>Читал Herb Sutter но не проникся , вот хочу узнать у того кто проникся , чем обосновано усложнение класса, оверхед на двойную диспечирезацию и т.п по сравнению с абстрактными интерфейсами .

АК>У меня мотивация для использования NVI прежде всего в явном разделение интерфейса (статичного) и реализации (специфичной для каждого класса полиморфной иерархии). Полезность этого разделения особенно проявляется, когда действие, которое мы хотим совершить над объектом, предполагает последовательность нескольких более мелких действий, специфичных для каждого объекта полиморфной иерархии. Отдавать эти мелкие действия на откуп пользователю класса чревато усложнением использования этого класса и ошибками.



Когда действие представляет последовательность более мелких методов — это называется шаблонный метод. И Саттер явно говорит, что NVI это не шаблонный метод, это lite версия. Он подчёркивает, что при NVI имеется именно одно действие.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Преимущества NVI в C++ (non virtual interface)
От: minorlogic Украина  
Дата: 29.04.06 18:10
Оценка:
Здравствуйте, srggal, Вы писали:

[...]
S>При использовании NVI ни потомки, ни тем более клиенты класса не смог самостоятельно вызвать функцию. Т.е. сам базовый класс определяеи момент вызова и его контекст, так сказать "жестко" закреплённое архитектурное решение.

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

А как быть с классами не предполагающими наследование ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: Преимущества NVI в C++ (non virtual interface)
От: minorlogic Украина  
Дата: 29.04.06 18:11
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Здравствуйте, minorlogic, Вы писали:


M>>http://www.gotw.ca/publications/mill18.htm

A>...
M>>Готов к конструктивной критике , в надежде на то , что разберусь в вопросе.

A>Ты невнимательно читал статью. Многие из твоих вопросов не имеют смысла. Причём здесь pimpl? При чём здесь противоречие архитектуре языка? Здесь концептуальная проблема. Открытые виртуальные функции играют сразу две роли: интерфейса и модификации поведения через наследуемые классы. Саттер очень ясно её описывает:

A>

A>// Example 1: A traditional base class.
A>//
A>class Widget
A>{
A>public:
A> // Each of these functions might optionally be
A> // pure virtual, and if so might or might not have
A> // an implementation in Widget; see Item 27 in [1].
A> //
A> virtual int Process( Gadget& );
A> virtual bool IsDone();
A> // ...
A>};

A>The problem is that "simultaneously" part, because each virtual function is doing two jobs: It's specifying interface because it's public and therefore directly part of the interface Widget presents to the rest of the world; and it's specifying implementation detail, namely the internally customizable behavior, because it's virtual and therefore provides a hook for derived classes to replace the base implementation of that function (if any). That a public virtual function inherently has two significantly different jobs is a sign that it's not separating concerns well and that we should consider a different approach.


A>Закрытие виртуальных методов позволяет убрать одну из ролей. Такие виртуальные методы уже не часть открытого интерфейса. Роль интерфейса играют невиртуальные методы. В этом и заключается смысл идиомы Non-Virtual Interface.


>>Т.е. рекомендация которая ЯВНО и насквозь противоречит архитектуре самого языка C++ , смотреть Страуструпа.


A>Тут ты загнул. Страуструп здесь не причем.


A>Ты преподносишь NVI как что-то новое, до сих пор невиданное и не особо нужное. Эта идиома широко применялась задолго до того, как Саттер начал её популизировать. Смотри стандартную библиотеку. IOStreams библиотека — это год 1995 от силы. basic_stream_buffer. Открытый интерфейс не виртуален. Модификация поведения производится через виртуальные защищённые методы. И так везде в стандартной библиотеке. Поищи хотя бы функции начинающиеся с do_ — они все защищённые виртуальные.


Ок. Спасибо огромное , я примерно все это уже себе представляю, но вы говорите про конкретную роль при использовании в иерархии классов.
Но

1. Почему совмещение ролей интерфейса и полиморфного поведения может считаться злом ??? вот это мне не совсем понятно .

2. А когда речь идет о классе который не предполагает наследование ?

З.Ы. я и сам когда то да применяю закрытые полиморфные функции , и представляю что это не новое решение. Но Сатер же говорит о применении этого патерна везде где только можно, вот это мне не понятно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: Преимущества NVI в C++ (non virtual interface)
От: minorlogic Украина  
Дата: 29.04.06 18:18
Оценка: 6 (1)
Здравствуйте, IROV.., Вы писали:

IRO>Здравствуйте, minorlogic, Вы писали:


M>>1. Неубедительная мотивация для использование NVI.


IRO>Для меня убедительная..


IRO>сравним.


IRO>это:

IRO>
IRO>class A
IRO>{
IRO>    virtual void Foo()
IRO>    {
IRO>        if(enable ==  false)
IRO>        { 
IRO>            Log << "Blah-Blah" << endl;
IRO>        }

IRO>        //TODO:

IRO>    }
IRO>};

IRO>class B
IRO>    : public A
IRO>{
IRO>    void Foo()
IRO>    {
IRO>        if(enable ==  false)
IRO>        { 
IRO>            Log << "Blah-Blah" << endl;
IRO>        }

IRO>        //TODO:
IRO>    }
IRO>};
IRO>

IRO>с вот этим:
IRO>
IRO>class A
IRO>{
IRO>    void Foo()
IRO>    {
IRO>        if( enable ==  false)
IRO>        { 
IRO>            Log << "Blah-Blah" << endl;
IRO>        }

IRO>        _Foo();
IRO>    }

IRO>    virtual void _Foo()
IRO>    {
IRO>        //TODO:
IRO>    }
IRO>};

IRO>class B
IRO>    : public A
IRO>{
IRO>    void _Foo()
IRO>    {
IRO>        //TODO:
IRO>    }
IRO>};
IRO>



IRO>+ Возможность создания префикса и постфикса к функции

IRO>+ Легко менять(сопровождать) префикс/постфикса при этом не боясь забыть гдето поменять.
IRO>+ Меньше кода! а значит меньше проблем на сопровождение.
IRO>+ Помогает избежать ошибок (забытые юзером проверки), если нужна обязательная валидация.

IRO>— Ущемляет права юзера на ликведацию пре/пост-фикса (может это и к лучему)


IRO>P.S. знаю _Foo писать не безопастно (чертов STL ).. просто для наглядности



а так ???

class A
{
public:
    virtual void Foo() //интерфейс
    {
        if( enable ==  false)
        { 
            Log << "Blah-Blah" << endl;
        }

        _Foo();
    }
protected:
    virtual void _Foo() //реализация
    {
        //TODO:
    }
};

class B
    : public A
{
protected:
    void _Foo()
    {
        //TODO:
    }
};


Это же очевидно , что если есть повторяющиеся действия , то необходимо выделить в отдельную функцию .

Но в последнем варианте , мы даем разработчику отнаследованному от нас и возможность исменить поведение как _Foo() так и Foo(), то есть больше свободы , то есть больше универсальности.

И опять же вопрос , ведь Сатер рекомендует это использовать не для часных случаев где это может понадобиться , а как общее правило.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[3]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 18:36
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Здравствуйте, srggal, Вы писали:


M>[...]

S>>При использовании NVI ни потомки, ни тем более клиенты класса не смог самостоятельно вызвать функцию. Т.е. сам базовый класс определяеи момент вызова и его контекст, так сказать "жестко" закреплённое архитектурное решение.

M>Ок. Принято , понял , то есть это закрепление некого архитектурного решения по декомпозиции , по использованию переопределенных методов тольок для фиксированного набора действий. Согласен с такой мотривировкой , но добавлю , что редко возникает такая необходимость .


M>А как быть с классами не предполагающими наследование ?


А зачем в классах, не предполагающих наследование, виртуальные функции?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 18:45
Оценка: +1
Здравствуйте, minorlogic, Вы писали:


M>Ок. Спасибо огромное , я примерно все это уже себе представляю, но вы говорите про конкретную роль при использовании в иерархии классов.

M>Но

M>1. Почему совмещение ролей интерфейса и полиморфного поведения может считаться злом ??? вот это мне не совсем понятно .


Это не то, что бы зло, по крайней мере всегда. Но.

1. Это разные сущности, а без NVI они сливаются в одну. Но т.к. сущности это всё-таки разные, то ничего не мешает одной из них впоследствие измениться.

2. В стандартном решении (без NVI) эти два интерфейса всегда насильно делают абсолютно одинаковыми, хотя по сути эти два интерфейса могли бы иметь немного различающие nativ'ные интерфейсы. Можно привести такие примеры: публичный интерфейс должен принимать указатель на объект, а приватный должен принимать ссылку на объект. Или публичный интерфейс должен принимать величину в секундах, а приватный — в миллисекундах. Могут быть более "сложные" примеры.
Это может быть из-за того, что публичный интерфейс часто страдает от необходимости обратной совместимости, а то время как в приватному интерфейсу это может (должно) ни в коей мере не относится.


M>2. А когда речь идет о классе который не предполагает наследование ?


А зачем в классах, не предполагающих наследование, виртуальные функции?



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 19:21
Оценка: 16 (2) +2 :)
Здравствуйте, minorlogic, Вы писали:

M> Но в последнем варианте , мы даем разработчику отнаследованному от нас и возможность исменить поведение как _Foo() так и Foo(), то есть больше свободы , то есть больше универсальности.


Больше универсальности — можно сделать правильно, а можно сделать неправильно. Зашибенская универсальность

Рассмотрим всем нам хорошо известный пример: CDlg::OnInitDialog()

Каких только извращений я не видел при перекрытии этой функции.
И так:

BOOL CMyDlg::OnInitDialog()
{
  CDlg::OnInitDialog();

  // свои действия

  return TRUE;
}


И так:

BOOL CMyDlg::OnInitDialog()
{
  // свои действия

  CDlg::OnInitDialog();
  return TRUE;
}


И так:

BOOL CMyDlg::OnInitDialog()
{
  // свои действия
  
  return CDlg::OnInitDialog();
}


И так:

BOOL CMyDlg::OnInitDialog()
{
  CDlg::OnInitDialog(); // CMyDlg унаследован не напрямую от CDlg, т.е. таким вызовом пропускаем обработку непосредственного родителя

  // свои действия

  return TRUE;
}


И все они неправильные! Правильный единственный вариант:

BOOL CMyDlg::OnInitDialog()
{
  BOOL res = CParentDlg::OnInitDialog(); // Надо внимательно следить, что бы здесь было имя именно непосредственного родителя

  // свои действия

  return res;  // Исхожу из того предположения, что обычно нет необходимости влиять на отображение фокуса
}


Я и сам так раньше не писал, и сейчас не всегда так пришу, просто потомучто влом. Влом заниматься тем, что меня не касается — вызывать какой-то метод какого-то класса (который ещё к тому же меняется), создавать дополнительную переменную.

Вот тебе и универсальность, о которой ты говоришь, — более половины всех перекрытий функции OnInitDialog(), которые я видел, были неправильные!

Если бы разработчик класса CDlg был примерным мальчиком и слушал Саттера (неважно, что он ещё об этом не написал в том момент ) и сделал бы NVI, то перекрытия функций OnInitDialog() выглядели бы просто так:

void CMyDlg::OnInitDialog()
{
  // свои действия
}


В этом коде просто нельзя сделать ошибку, т.к. ничего лишнего делать не надо!

Вот и думай после этого об универсальности.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Преимущества NVI в C++ (non virtual interface)
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 29.04.06 20:31
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Андрей Коростелев, Вы писали:


АК>>Здравствуйте, minorlogic, Вы писали:


M>>>Неубедительная мотивация для использование NVI.

M>>>Читал Herb Sutter но не проникся , вот хочу узнать у того кто проникся , чем обосновано усложнение класса, оверхед на двойную диспечирезацию и т.п по сравнению с абстрактными интерфейсами .

АК>>У меня мотивация для использования NVI прежде всего в явном разделение интерфейса (статичного) и реализации (специфичной для каждого класса полиморфной иерархии). Полезность этого разделения особенно проявляется, когда действие, которое мы хотим совершить над объектом, предполагает последовательность нескольких более мелких действий, специфичных для каждого объекта полиморфной иерархии. Отдавать эти мелкие действия на откуп пользователю класса чревато усложнением использования этого класса и ошибками.


R>Когда действие представляет последовательность более мелких методов — это называется шаблонный метод. И Саттер явно говорит, что NVI это не шаблонный метод, это lite версия. Он подчёркивает, что при NVI имеется именно одно действие.

R>

Не совсем так. Саттер использует один и тот же механизм по названием Template Method несколько для других целей, нежели его использовали Гамма и сотоварищи. Саттер не акцентируется на том, что действие может потребовать последовательность более мелких действий, так как прежде всего хочет сказать, что привычный нам дизайн через открытые виртуальные функции чреват смешеним интерфейса и полиморфного поведения. Потому я умышленно подчеркнул Гаммовскую составляющую.

-- Андрей
Re[4]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 20:46
Оценка:
Здравствуйте, Андрей Коростелев, Вы писали:

АК>Здравствуйте, remark, Вы писали:


R>>Здравствуйте, Андрей Коростелев, Вы писали:


АК>>>Здравствуйте, minorlogic, Вы писали:


M>>>>Неубедительная мотивация для использование NVI.

M>>>>Читал Herb Sutter но не проникся , вот хочу узнать у того кто проникся , чем обосновано усложнение класса, оверхед на двойную диспечирезацию и т.п по сравнению с абстрактными интерфейсами .

АК>>>У меня мотивация для использования NVI прежде всего в явном разделение интерфейса (статичного) и реализации (специфичной для каждого класса полиморфной иерархии). Полезность этого разделения особенно проявляется, когда действие, которое мы хотим совершить над объектом, предполагает последовательность нескольких более мелких действий, специфичных для каждого объекта полиморфной иерархии. Отдавать эти мелкие действия на откуп пользователю класса чревато усложнением использования этого класса и ошибками.


R>>Когда действие представляет последовательность более мелких методов — это называется шаблонный метод. И Саттер явно говорит, что NVI это не шаблонный метод, это lite версия. Он подчёркивает, что при NVI имеется именно одно действие.

R>>

АК>Не совсем так. Саттер использует один и тот же механизм по названием Template Method несколько для других целей, нежели его использовали Гамма и сотоварищи. Саттер не акцентируется на том, что действие может потребовать последовательность более мелких действий, так как прежде всего хочет сказать, что привычный нам дизайн через открытые виртуальные функции чреват смешеним интерфейса и полиморфного поведения. Потому я умышленно подчеркнул Гаммовскую составляющую.



Книжки под рукой нет, поэтому процитировать не смогу. Но в голове всплывает именно что-то типа того, что я написал выше. Т.е. он пишет, что это именно замена одной функции.


АК>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Преимущества NVI в C++ (non virtual interface)
От: minorlogic Украина  
Дата: 29.04.06 20:49
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, minorlogic, Вы писали:


M>>Здравствуйте, srggal, Вы писали:


M>>[...]

S>>>При использовании NVI ни потомки, ни тем более клиенты класса не смог самостоятельно вызвать функцию. Т.е. сам базовый класс определяеи момент вызова и его контекст, так сказать "жестко" закреплённое архитектурное решение.

M>>Ок. Принято , понял , то есть это закрепление некого архитектурного решения по декомпозиции , по использованию переопределенных методов тольок для фиксированного набора действий. Согласен с такой мотривировкой , но добавлю , что редко возникает такая необходимость .


M>>А как быть с классами не предполагающими наследование ?


R>А зачем в классах, не предполагающих наследование, виртуальные функции?


Эээээ ... Интерфейсы ? Инкапсуляция ? Имееется ввиду , что интерфейс будет реализован один раз , и не предполагает дальнейших от него реализаций.

В C++ виртуальные функции служат как для полиморфизма , так и разделения интерфейса и реализации.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[4]: Преимущества NVI в C++ (non virtual interface)
От: minorlogic Украина  
Дата: 29.04.06 21:02
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, minorlogic, Вы писали:


M>> Но в последнем варианте , мы даем разработчику отнаследованному от нас и возможность исменить поведение как _Foo() так и Foo(), то есть больше свободы , то есть больше универсальности.


R>Больше универсальности — можно сделать правильно, а можно сделать неправильно. Зашибенская универсальность


R>Рассмотрим всем нам хорошо известный пример: CDlg::OnInitDialog()


R>Каких только извращений я не видел при перекрытии этой функции.

R>И так:

R>
R>BOOL CMyDlg::OnInitDialog()
R>{
R>  CDlg::OnInitDialog();

R>  // свои действия

R>  return TRUE;
R>}
R>


R>И так:


R>
R>BOOL CMyDlg::OnInitDialog()
R>{
R>  // свои действия

R>  CDlg::OnInitDialog();
R>  return TRUE;
R>}
R>


R>И так:


R>
R>BOOL CMyDlg::OnInitDialog()
R>{
R>  // свои действия
  
R>  return CDlg::OnInitDialog();
R>}
R>


R>И так:


R>
R>BOOL CMyDlg::OnInitDialog()
R>{
R>  CDlg::OnInitDialog(); // CMyDlg унаследован не напрямую от CDlg, т.е. таким вызовом пропускаем обработку непосредственного родителя

R>  // свои действия

R>  return TRUE;
R>}
R>


R>И все они неправильные! Правильный единственный вариант:


R>
R>BOOL CMyDlg::OnInitDialog()
R>{
R>  BOOL res = CParentDlg::OnInitDialog(); // Надо внимательно следить, что бы здесь было имя именно непосредственного родителя

R>  // свои действия

R>  return res;  // Исхожу из того предположения, что обычно нет необходимости влиять на отображение фокуса
R>}
R>


R>Я и сам так раньше не писал, и сейчас не всегда так пришу, просто потомучто влом. Влом заниматься тем, что меня не касается — вызывать какой-то метод какого-то класса (который ещё к тому же меняется), создавать дополнительную переменную.


R>Вот тебе и универсальность, о которой ты говоришь, — более половины всех перекрытий функции OnInitDialog(), которые я видел, были неправильные!


R>Если бы разработчик класса CDlg был примерным мальчиком и слушал Саттера (неважно, что он ещё об этом не написал в том момент ) и сделал бы NVI, то перекрытия функций OnInitDialog() выглядели бы просто так:


R>
R>void CMyDlg::OnInitDialog()
R>{
R>  // свои действия
R>}
R>


R>В этом коде просто нельзя сделать ошибку, т.к. ничего лишнего делать не надо!


R>Вот и думай после этого об универсальности.


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

Опять же наследование может быть многоуровневым.

void CMyDlgDerived::CMyDlg()
   CMyDlg::OnInitDialog();
     // or CParentDlg::OnInitDialog(); ???

  // свои действия
}


Или я опять что то не додумал ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[5]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 22:20
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Здравствуйте, remark, Вы писали:


R>>Здравствуйте, minorlogic, Вы писали:


M>>>Здравствуйте, srggal, Вы писали:


M>>>[...]

S>>>>При использовании NVI ни потомки, ни тем более клиенты класса не смог самостоятельно вызвать функцию. Т.е. сам базовый класс определяеи момент вызова и его контекст, так сказать "жестко" закреплённое архитектурное решение.

M>>>Ок. Принято , понял , то есть это закрепление некого архитектурного решения по декомпозиции , по использованию переопределенных методов тольок для фиксированного набора действий. Согласен с такой мотривировкой , но добавлю , что редко возникает такая необходимость .


M>>>А как быть с классами не предполагающими наследование ?


R>>А зачем в классах, не предполагающих наследование, виртуальные функции?


M>Эээээ ... Интерфейсы ? Инкапсуляция ? Имееется ввиду , что интерфейс будет реализован один раз , и не предполагает дальнейших от него реализаций.


M>В C++ виртуальные функции служат как для полиморфизма , так и разделения интерфейса и реализации.


Аааа. Смысл вопроса я теперь понял.
[оффтоп]
Но С++ так же не определяет и понятие интерфейма. Это будет просто класс, от которого ты отнаследуешь реализаицю.
[/оффтоп]

NVI имеет смысл только для того первого применения виртуальных функций, которое для динамического полиморфизма.
В интерфейсном классе нет смыcла применять NVI. Т.к. просто нет смысла.
Можно, конечно вставить в него чисто форвардящие функции, но смысла всё равно нет. Только лишнаяя работа.
NVI имеет смысл, когда имеется или возможна в будущем некая общая функциональность.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Преимущества NVI в C++ (non virtual interface)
От: remark Россия http://www.1024cores.net/
Дата: 29.04.06 22:26
Оценка:
Здравствуйте, minorlogic, Вы писали:

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

M>Если есть часть которую необходимо выполнить всегда , она вообще не должна наследоваться и быть в интерфейсе, ни в NVI ни в виртуальном.

Не понял функция должна быть в интерфейсе, но не в виртуальном, не в не виртуальном... Так в каком же интерфейсе она должна быть???

Вообще, это как раз и называется NVI, когда общая часть "не наследуется" и не может перекрываться.


M>Опять же наследование может быть многоуровневым.


С этой проблемой NVI, к сожалению, не может справиться. Только если делать так же несколько уровней NVI, что конечно же не очень красиво.


M>
M>void CMyDlgDerived::CMyDlg()
M>   CMyDlg::OnInitDialog();
M>     // or CParentDlg::OnInitDialog(); ???

M>  // свои действия
M>}
M>



Пример забавный



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Преимущества NVI в C++ (non virtual interface)
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 29.04.06 22:40
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Здравствуйте, alexeiz, Вы писали:

M>Но Сатер же говорит о применении этого патерна везде где только можно, вот это мне не понятно.

Саттер прав, думаю, тебя в этом убедили в соседних ветках. От себя добавлю, что один, хотя и не очень серьезный недостаток у NVI по сравнению со стандартным подходом все-таки есть — это отсутствие ковариантности.
-- Андрей
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.