2013-05-05 4 views
3

Это вопрос, который немного беспокоит меня, но не смог найти лучший способ справиться с этим. Я пытаюсь показать это на примере.C++ пространство имен и иерархия классов

Я разрабатываю графическую библиотеку со многими классами. Некоторые из классов «части» отношений друг с другом, как этот 3 класс:

namespace MyGraphicsLibrary 
{ 

class MatrixStack 
{ 

}; 

class Transform 
{ 
    MatrixStack mMatrixStack; 
}; 

class Renderer 
{ 
    Transform mTransform; 
}; 

} 

Renderer класса для пользователей, чтобы использовать, но я не хочу, чтобы они видели Transform, MatrixStack классов, когда они ищут MyGraphicsLibrary. Последние два класса предназначены только для класса Renderer, а не для пользователей.

Здесь я пытаюсь сделать две вещи:

  1. Скрытие Transform, MatrixStack классы от пользователей.

  2. Отразить "часть" иерархия классов.

Я попробовал следующее, чтобы решить эту проблему:

  1. Лучшее решение для меня было бы частные вложенные классы, как это было бы показать пользователю, что вложенный класс является частным, а также отражает иерархию, если вы просто посмотрите на объявление класса Renderer. Следующий пост на самом деле заставляет меня неопределенным, что является хорошим решением: Pros and cons of using nested C++ classes and enumerations?

  2. Я пытался поставить Transform, MatrixStack в другое пространство имен называется Private. Таким образом, пользовательский поиск MyGraphicsLibrary пространства имен будет содержать пространство имен Private, охватывающее все классы, которые не предназначены для пользователей. Это хорошо, но есть много других классов с той же проблемой, и я быстро заполняю пространство имен Private классами, которые не имеют никакого отношения друг к другу. Здесь я только мог придумать уродливые решения, как вводящие вложенных пространства имен:

    namespace MyGraphicsLibrary 
    { 
        //private classes belonging to Renderer class 
        namespace PrivateRenderer 
        { 
        class MatrixStack 
        { 
        }; 
    
         class Transform 
         { 
          MatrixStack mMatrixStack; 
         }; 
        } 
    
        //public classes for users 
        class Renderer 
        { 
        Transform mTransform; 
        }; 
    } 
    

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

ответ

1

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

Следовательно, тип будет виден везде, где вы хотите использовать класс контейнера.

У вас есть следующие варианты:

  1. сигнал, что они не для общественного пользования через именование. Либо помещайте в пространство имен (например, детали в boost), либо префикс/суффикс его имени.
  2. Используйте технику, которая запрещает клиентам использовать этот класс. Сделайте все функции-члены частными и объявите друга класса контейнера. Идиома адвоката-клиента - более сложный способ тонкого контроля доступа.
  3. Store Transform косвенно (указатель или ссылка), поэтому вам не нужно его определение в публичном заголовке. Это pimpl. Вариант этого, если публичный тип - это интерфейс, базовый класс фактической реализации Transform.

Пространство имен: определенно плохая идея в заголовке. Безымянные пространства имен похожи на C static: они получают генерируемый компилятором идентификатор, который гарантированно будет уникальным для данной единицы перевода. У вас будет столько различных типов преобразования, сколько мест, в которые вы включили его определение.

+0

Спасибо, я отмечаю это как ответ, поскольку он предлагает больше вариантов. Раньше я читал о pimpl, но мне кажется, что мне нужно в это время заглянуть. – Avithohol

0

Используйте анонимное пространство имен:

namespace MyGraphicsLibrary 
{ 
    namespace 
    { 
     class MatrixStack 
     { 

     }; 

     class Transform 
     { 
      MatrixStack mMatrixStack; 
     }; 
    } 

    class Renderer 
    { 
     Transform mTransform; 
    }; 

} 
+0

благодарю вас за ваше время, я иду с jmihalicza, хотя – Avithohol

2

вы можете использовать PIMPL- (называемый также непрозрачный указатель) идиомы. В шляпе вы можете полностью скрыть классы от пользователя следующим образом:

В вашем общедоступном заголовке (в вашей включенной папке): Renderer.ч

class RendererImpl; // forward declaration of internal render structure 

//public classes for users 
class Renderer 
{ 
    public: 
    Renderer(); 
    ~Renderer(); 
    // public interface comes here and delegates all calls to RendererImpl (have to be implemented in cpp) 

    RendererImpl* renderer; // better use something like QScopedPointer here 
}; 

СРР:

#include "RendererImpl.h" // your actual renderer that 

Renderer::Renderer() 
:renderer(new RendererImpl) 
{} 
Renderer::~Renderer() 
{ 
    delete renderer; 
} 

Реализация может быть полностью скрыта от API. Заголовки должны быть отделены от реальных интерфейсов.

+0

благодарю вас за ваше время Влад, я иду с jmihalicza, хотя – Avithohol

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