C ++ класс, который будет использоваться только другим классом - PullRequest
2 голосов
/ 20 декабря 2010

Я создаю класс (класс A), который должен иметь возможность создавать несколько экземпляров другого класса (класса B) в ходе его работы, но класс B используется только несколькими функциями-членами класс А, и никогда не используется за пределами класса. Как лучше всего определить класс B? Это практично / разумно сделать его частным членом класса А? Это предназначение вложенных классов или я расстаюсь с духом конструкции?

Спасибо, Wyatt

РЕДАКТИРОВАТЬ: При дальнейшем рассмотрении, я на самом деле не спрашиваю о наилучшей практике, так как это для личного проекта. Я хочу включить класс B в качестве члена класса A с точки зрения инкапсуляции - просто кажется разумным, что класс, который полностью подчинен, должен фактически быть частью его собственного класса.

Что мне интересно, так это разумный вариант использования для вложенных классов или нет? Если нет, какова цель вложенных классов?

Ответы [ 6 ]

3 голосов
/ 20 декабря 2010

Одна возможность состоит в том, чтобы определить пространство имен с именем detail внутри пространства имен, в которое вы помещаете свои классы.например,

// public_namespace_detail.hpp
namespace public_namespace
{
    namespace detail
    {
        class B
        {
          ...
        };

    }
}

// public_namespace.hpp
#include "public_namespace_detail.hpp"

namespace public_namespace
{
    class A
    {
       detail::B b;
       ...       
    };
}
2 голосов
/ 20 декабря 2010

Я бы просто сделал class B совершенно не связанным с class A - если ничего другого, то будет проще писать тесты, если вы сможете тестировать class A и class B отдельно. Если вы не хотите идти по этому пути, не позволяйте никому создавать экземпляр class B, кроме class A, определив class B, сделав его закрытым конструктором, а затем сделав class A a friend.

.
1 голос
/ 20 декабря 2010

У вас есть несколько вариантов:

  1. частное наследство: class A : private B {};

  2. вложенный класс: class A { class B { /* etc */ }; };

  3. Добрый старый частный член класса B из класса A : class A { B b; };

Лично я бы пошел с вложенным классом, если вы на 100% уверены, что он не нужен снаружи.

0 голосов
/ 20 декабря 2010

Да, с вложенным классом здесь все в порядке.

Обратите внимание, что для обеспечения организованности кода я бы не поместил определение B в A.Вместо этого:

class A
{
    class B;
};

class A::B
{
};

Помимо прочего, это позволяет помещать определение класса A::B в файл реализации А.

РЕДАКТИРОВАТЬ: Поскольку, как представляется, существует некоторая путаница относительно того,вложенный класс получает доступ к закрытым членам содержащего класса, я предоставляю фрагмент кода, чтобы доказать, что он делает:

class A
{
    int x;

    class B
    {
        int func(A* p) { return p->x; }
    };
};

Вариант без встроенного определения A::B, также допускается:

class A
{
    int x;

    class B;
};

class A::B
{
    int func(A* p) { return p->x; }
};
  • Comeau: Принято (оба варианта)

Ваши результаты теста Comeau C / C ++ следующие:

Comeau C / C ++ 4.3.10.1 (6 октября 2008 11:28:09) для ONLINE_EVALUATION_BETA2 Copyright 1988-2008 Comeau Computing.Все права защищены.РЕЖИМ: строгие ошибки C ++ noC ++ 0x_extensions

В строгом режиме, с -tused, Compile успешно (но помните, онлайн-компилятор Comeau не связывает).Скомпилировано с расширениями C ++ 0x DISabled.

0 голосов
/ 20 декабря 2010

Я бы переместил его за пределы B, так как в противном случае он будет открыт для других классов через заголовочный файл A (нравится вам это или нет). Иначе говоря, если вы измените реализацию B, то клиенты A должны перекомпилировать - поскольку B был объявлен внутри A.

Структура моего проекта должна прояснить, что заголовочный файл для B не должен использоваться другими классами. Например, у меня есть папка с именем «export», в которую я помещаю все мои заголовочные файлы, которые я собираюсь опубликовать за пределами проекта. Очевидно, что заголовок B. там не будет найден.

На другом языке, который не использует файлы заголовков, например C #, я буду случайно помещать B внутри A, если B довольно мало - возможно, не более 6-10 строк объявления.

0 голосов
/ 20 декабря 2010

Общее правило для меня заключается в том, что если я обнаружил, что у меня возникла трудная проблема с наследованием, то я, вероятно, посмотрел на проблему неправильно.

Есть ли способ, которым вы можете реструктурировать свою программу, чтобы классы были менее "связанными"? И.Е. Можете ли вы переместить функции из класса A, которые ссылаются на класс B (и поместить их в B)?

...