нужны - наследование вложенных классов c++




Плюсы и минусы использования вложенных классов C++ и перечислений? (9)

Каковы плюсы и минусы использования вложенных открытых классов C ++ и перечислений? Например, предположим, что у вас есть класс под названием printer , и этот класс также хранит информацию о выходных лотках, вы можете:

class printer
{
public:
    std::string name_;

    enum TYPE
    {
        TYPE_LOCAL,
        TYPE_NETWORK,
    };

    class output_tray
    {
        ...
    };
    ...
};

printer prn;
printer::TYPE type;
printer::output_tray tray;

В качестве альтернативы:

class printer
{
public:
    std::string name_;
    ...
};

enum PRINTER_TYPE
{
    PRINTER_TYPE_LOCAL,
    PRINTER_TYPE_NETWORK,
};

class output_tray
{
    ...
};

printer prn;
PRINTER_TYPE type;
output_tray tray;

Я вижу преимущества вложенности частных enums / classes, но когда дело доходит до публичных, офис разделен - кажется, это скорее выбор стиля.

Итак, что вы предпочитаете и почему?


Вложенные классы

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

Представим следующий код:

class A
{
   public :
      class B { /* etc. */ } ;

   // etc.
} ;

Или даже:

class A
{
   public :
      class B ;

   // etc.
} ;

class A::B
{
   public :

   // etc.
} ;

Так:

  • Привилегированный доступ: A :: B имеет привилегированный доступ ко всем членам A (методы, переменные, символы и т. Д.), Что ослабляет инкапсуляцию
  • Область A является кандидатом для поиска символа: код изнутри B будет видеть все символы из A в качестве возможных кандидатов для поиска символа, что может смутить код
  • forward-declaration: нет возможности переадресовывать A :: B без полного объявления A
  • Расширяемость: невозможно добавить еще один класс A :: C, если вы не являетесь владельцем A
  • Многословность кода: помещение классов в классы только увеличивает количество заголовков. Вы все же можете разделить это на несколько объявлений, но нет возможности использовать псевдонимы, импорты или использование имен, подобных пространству имен.

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

Кроме того, он пахнет как неуклюжая попытка имитировать пространство имен без использования пространств имен C ++.

На стороне pro, вы изолируете этот код, и если он закрыт, сделайте его непригодным, но из класса «снаружи» ...

Вложенные перечисления

Плюсы: Все.

Кон: Ничего.

Тот факт, что элементы перечисления будут загрязнять глобальный масштаб:

// collision
enum Value { empty = 7, undefined, defined } ;
enum Glass { empty = 42, half, full } ;

// empty is from Value or Glass?

Ony, помещая каждое перечисление в другое пространство имен / класс, позволит вам избежать этого столкновения:

namespace Value { enum type { empty = 7, undefined, defined } ; }
namespace Glass { enum type { empty = 42, half, full } ; }

// Value::type e = Value::empty ;
// Glass::type f = Glass::empty ;

Обратите внимание, что C ++ 0x определяет перечисление класса:

enum class Value { empty, undefined, defined } ;
enum class Glass { empty, half, full } ;

// Value e = Value::empty ;
// Glass f = Glass::empty ;

именно для таких проблем.


Visual Studio 2008, похоже, не может обеспечить intellisense для вложенных классов, поэтому я перешел на идиому PIMPL в большинстве случаев, когда у меня был вложенный класс. Я всегда помещаю перечисления в класс, если он используется только этим классом или вне класса в том же пространстве имен, что и класс, когда более одного класса использует перечисление.


Для меня большой конфликт с внешним миром заключается в том, что он становится частью глобального пространства имен. Если перечисление или связанный класс действительно применимы только к классу, в котором он находится, тогда это имеет смысл. Таким образом, в принтере все, что включает принтер, будет знать о наличии полного доступа к enum PRINTER_TYPE, где это действительно не нужно знать об этом. Я не могу сказать, что я когда-либо использовал внутренний класс, но для перечисления это кажется более логичным, чтобы держать его внутри. Как указывал еще один плакат, также неплохо использовать пространства имен для группировки подобных элементов, так как засорение глобального пространства имен действительно может быть плохой. Я ранее работал над крупными проектами, и только для создания полного полного списка в глобальном пространстве имен требуется 20 минут. По-моему, вложенные enums и namespaced classes / structs, вероятно, являются самым чистым подходом.


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

Это когда вы хотите использовать «внутренний» класс как самостоятельный объект, который может начать становиться немного манкированным, и вы должны начать писать процедуры экстрактора / вставки. Некрасивая ситуация.


Нет никаких плюсов и минусов, связанных с использованием вложенных открытых классов C ++. Есть только факты. Эти факты утверждены стандартом C ++. Независимо от того, зависит ли факт от вложенных общедоступных классов C ++ как pro или con, зависит от конкретной проблемы, которую вы пытаетесь решить. Приведенный вами пример не позволяет судить о том, подходят ли вложенные классы или нет.

Один факт о вложенных классах состоит в том, что они имеют привилегированный доступ ко всем членам класса, к которому они принадлежат. Это con, если вложенные классы не нуждаются в таком доступе. Но если вложенный класс не нуждается в таком доступе, он не должен быть объявлен как вложенный класс. Бывают ситуации, когда класс A хочет предоставить привилегированный доступ к некоторым другим классам B. Существует три решения этой проблемы

  1. Сделайте B другом A
  2. Сделайте B вложенным классом A
  3. Выполните методы и атрибуты, необходимые B , публичные члены A.

В этой ситуации это № 3, которая нарушает инкапсуляцию, потому что А имеет контроль над своими друзьями и над его вложенными классами, но не над классами, которые называют его общедоступными методами или получают доступ к своим публичным атрибутам.

Еще один факт о вложенных классах заключается в том, что невозможно добавить еще один класс A :: C как вложенный класс A, если вы не являетесь владельцем A. Однако это вполне разумно, потому что вложенные классы имеют привилегированный доступ. Если бы было возможно добавить A :: C как вложенный класс A , то A :: C может обмануть A в предоставлении доступа к привилегированной информации; и что вы нарушаете инкапсуляцию. Это в основном то же самое, что и с объявлением friend : декларация friend не предоставляет вам никаких особых привилегий, которые ваш друг скрывает от других; это позволяет вашим друзьям получать информацию, которую вы скрываете от своих друзей. В C ++, называя кого-то друга альтруистическим актом, а не эгоистичным. То же самое справедливо для того, чтобы класс был вложенным классом.

Другие факты о вложенных публичных классах:

  • Область A является кандидатом на поиск символа B : если вы этого не хотите, сделайте B другом A вместо вложенного класса. Однако есть случаи, когда вы хотите точно такого рода поиск символов.
  • A :: B не может быть объявлен вперед: A и A :: B плотно связаны. Возможность использовать A :: B, не зная А , только скроет этот факт.

Подводя итог этому: если инструмент не соответствует вашим потребностям, не обвиняйте инструмент; обвините себя в использовании инструмента; другие могут иметь разные проблемы, для которых инструмент совершенен.


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


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


Только проблема с вложенными классами, с которой я столкнулась, заключалась в том, что C ++ не позволяет ссылаться на объект охватывающего класса во вложенных функциях класса. Мы не можем сказать «Enclosing :: this»

(Но, может быть, есть способ?)


Я согласен с сообщениями, защищающими вложение вашего перечисления в класс, но бывают случаи, когда имеет смысл не делать этого (но, пожалуйста, по крайней мере, поместить его в пространство имен). Если несколько классов используют перечисление, определенное в другом классе, то эти классы напрямую зависят от этого другого конкретного класса (которому принадлежит перечисление). Это, безусловно, представляет собой недостаток дизайна, поскольку этот класс будет отвечать за это перечисление, а также за другие обязанности.

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







nested