Как разбить объявление класса и его реализацию?

Я пытаюсь разбить объявление шаблона класса A и его реализацию на .h и .cpp файлы. Проблема в том, что в моем классе содержится приватное поле некого другого класса B, который должен быть недоступен пользователю.

Применительно к C++ я хочу скрыть этот класс B посредством объявления его в приватной секции класса А и реализации его в файле .h . Но компилятор выдает ошибку и я, хоть убей, не понимаю как мне тогда разбить мой класс А на два файла

Если описывать полностью...

Я реализую очередь на списке. У меня есть класс очереди Queue, который инкапсулирует объект класса Node и работает с ним. Задача заключается в том, чтобы сделать класс Node недоступным пользователю.

Queue.h
template<class T>
class Queue {
public:
    bool push(const T &data) noexcept;

    bool pop(T &data) noexcept;

private:
    template<class TNode> class Node;

    Node<T> *head = nullptr;
    Node<T> *tail = nullptr;
};


Queue.cpp
#include "Queue.h"

template<class T>
class Queue<T>::Node {
public:
    explicit Node(const T &data) : _data(data) {};

    Node(const T &data, Node<T> *next) : _data(data), _next(next) {};

    const T &getData() const { return this->_data; }

    Node<T> *getNext() const { return this->_next; }

    void setNext(Node<T> *next) { this->_next = next; }


private:
    Node<T> *_next = nullptr;
    T _data;
};

template<class T>
bool Queue<T>::push(const T &data) {/*some realization*/}

template<class T>
bool Queue<T>::pop(T &data) noexcept {/*some realization*/}



Упрощенная модель:
template<class T>
class A {
private:
    template<class TB> class B;
    B<T> b1;
};

template<class T>
class A<T>::B<T> {
private:
    T data1;
    T data2
};


Здесь на строчке class A<T>::B<T> компилятор ругается. Как правильно реализовать класс B? Или может существуют другие способы инкапсуляции класса в модуле?
  • Вопрос задан
  • 105 просмотров
Решения вопроса 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Вообще тут есть другая проблема, с которой вы столкнетесь. Если у вас определение шаблона и реализация в разных файлах, то будут ошибки на этапе линковки. Компилятор, когда будет обрабатывать cpp файл не увидит никаких использований шаблона и с чистым сердцем не сгенерирует никаких его специализаций. Потом линкер не сможет найти нужную реализацию и ругнется.

Чтобы это исправить нужно или засунуть все в h файл, или в cpp файле прописать специализации шаблона со всеми типами, которые где-либо еще используются, вот так:
using A<int>;
using A<double>;
// etc


Далее, как именно и зачем вы хотите этот внутренний класс скрыть?
Иногда вам может быть достаточно сделать член этого типа private и все. Факт того, что кто-то где-то сможет завести переменную этого типа обычно не является проблемой. Для списка уж точно. Если же это проблема и внутренний класс является friend внешнего и что-то такое делает, что нарушает инкапсуляцию (например при учнитожении, что-то меняет в родительском классе), то просто сделав вложенный класс private, вы ничего не добъетесь. Переменные этого типа все-равно можно будет использовать и к ним обращатся (иногда через хаки). Обычно у внутренних классов просто делают приватным конструктор и нужные методы и прописывают внешний класс как friend. Тогда вы в самом классе сможете переменные этого типа создавать и использовать, но никто снаружи ничего с ним сделать не может.

И кстати, в вашем случае вам совсем нет смысла делать вложенный класс шаблоном. Он уже в шаблоне же, просто используйте внутри тип T.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@12rbah
Хотел бы добавить информацию к ответу выше, т.к. поддерживать специализации бывает не очень удобно, то можно сделать отдельный файл с определениями функций шаблонов, для указания того, что там лежат именно шаблоны расширение у таких файлов ставят ".inl". Но есть особенность, которая заключается в том, что этот файл подключается в конце, выглядит это примерно так:
#ifndef example
#define example

template <class T>
class A
{
//....
}

//в этом файле лежат определения шаблонных функций для A
#include "template.inl"


#endif
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы