2010-01-28 2 views
6

Я читал статью о интерфейсах на C++ (http://accu.org/index.php/journals/233), и я полностью потерян в той части, где говорится, что все виртуальные функции-члены должны быть закрытыми (раздел «Усиление разделения» «). Это просто не имеет смысла для меня вообще.вопросы о статье, представляющей интерфейс C++

По мнению автора, код выглядит так:

class shape { 
public: 
    virtual ~shape(); 
    virtual void move_x(distance x) = 0; 
    virtual void move_y(distance y) = 0; 
    virtual void rotate(angle rotation) = 0; 
    //... 
}; 

class line : public shape { 
public: 
    line(point end_point_1, point end_point_2); 
    //... 
private: 
    virtual ~line(); 
    virtual void move_x(distance x); 
    virtual void move_y(distance y); 
    virtual void rotate(angle rotation); 
    //... 
}; 

Таким образом, мы имеем чистую виртуальную функцию, которая является общественным, и ее реализации (в классе линии), которая является частным.

Может ли кто-нибудь объяснить, как можно вызвать функцию move_x? Его спецификатора доступа является частным, это приведет к ошибке, если я пытаюсь сделать это:

line my_line(point(0,0), point(1,2)); 
my_line.move_x(-1); // does not compile 

Точно так же это правильно сказать, что интерфейс рисования (см ранее в статье) не может получить доступ к этим функциям либо?

спасибо.

+1

Я просто пытался создать код, и он не скомпилирован, потому что деструктор является закрытым ... – Patrick

ответ

6

Идея состоит в том, что вы использовали бы эти методы с помощью ссылки или указателя на shape.

shape &s = my_line; 
s.move_x(-1); 

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

+3

Считается, что лучше привычка программирования заставить программиста (самого себя) использовать только интерфейс. – Ben

+0

Не могу сказать, что мне очень нравится идея; если я хочу, чтобы линия была то, что я хочу, а не фигура, которая является линией. Если у меня есть функция, которая нуждается только в методах, предоставляемых формой, я передам строку в эту функцию как форму, просто не могу понять, почему вы это сделаете, +1 для объяснения. – Patrick

+0

Я согласен, что это не жизненный совет. Как показано в двух строках выше, это фактически не ограничивает ничего - просто вызывает незначительные неудобства, если пользователь, похоже, должен нарушить правило. –

2

Я думаю, что в этой статье подчеркивается целесообразность хорошо в этой цитате:

Теперь только пользователь вещи можно сделать с линии создавать экземпляры этого. Все использование должно осуществляться через его интерфейс, то есть , что обеспечивает более сильное разделение интерфейса/реализации по умолчанию . Перед тем, как покинуть эту тему, важно получить что-то прямое: Точка принудительного разделения интерфейса/реализации равна , чтобы не сообщать пользователям, что делать. Скорее, Целью является то, что логическое разделение - код объясняет, что ключевая абстракция имеет форму , и эта линия служит для предоставления формы .

То есть, line не является само по себе интересным. Это всего лишь реализация интерфейса shape, и могут быть другие реализации. Вас особенно интересует интерфейс shape. Следовательно, вы должны получать доступ только к реализации через этот интерфейс, а не как отдельный класс.

4

Если у вас есть объект line, возможно, у вас возникнет соблазн вызвать его методы. Но если единственный способ получить их - попросить интерфейс shape, тогда объект будет выглядеть как объект как нечто похожее на коллекцию интерфейсов.

Это имеет смысл, если вы представляете себе линию, реализующую более одного интерфейса.

3

Этот совет применим только к однородным иерархиям, то есть к иерархиям, в которых производные классы не вводят никаких новых функций (за исключением конструкторов) и просто переопределяют функции базового класса. В этом случае вам явно не нужно работать с экземпляром line напрямую - только с помощью указателя/ссылки на shape.

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

Дальнейшая разработка этой идеи - менее радикальная и пригодная для использования в большем количестве контекстов - Non-Virtual Interface (NVI) Herb Sutter.

+0

+1, он также препятствует использованию ковариантных типов возврата –

Смежные вопросы