2016-01-30 6 views
2

В моей математической библиотеке, которую я создаю на C++, у меня есть класс Quaternion и класс Vector3. Они раскладывают так:Круговые зависимости между встроенными файлами

Vector3.hpp:

#pragma once 

template<typename T> 
struct Vector3 
{ 
    //... 
}; 

template<typename T> 
Vector3<T> operator+(Vector3<T> lhs, Vector3<T> rhs); 

#include "Vector3.inl" 

Vector3.inl

template<typename T> 
Vector3<T> operator+(Vector3<T> lhs, Vector3<T> rhs) 
{ 
    return Vector3<T>(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z); 
} 

//... 

Quaternion класс выложенный то же самое.

В настоящее время у меня есть класс Quaternion с использованием класса Vector3 для параметров функции, поэтому он #include с заголовком Vector3.hpp. Но теперь мне нужно использовать класс Quaternion в моем классе Vector3 для реализации определенных функций.

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

Как вы решаете такую ​​циклическую зависимость, когда я могу использовать только заголовочные/встроенные файлы?

+0

Почему вы * должны * использовать только заголовочные/встроенные файлы? По крайней мере, вам стоит переместить строку '#include 'Vector3.inl' из' Vector3.hpp' в файл '.cpp' пользователя. – harper

ответ

0

Лучший способ справиться с круговой зависимостью - это избежать этого во-первых! Было бы разумно занять некоторое время, чтобы пересмотреть дизайн, изменить функциональность, классы разделения и т. Д.

Давайте предположим ситуацию без круговой зависимости выглядит следующим образом:

template <typename T> 
struct Vector{ 
... 
}; 

template<typename T> 
struct VectorUser{ 
    Vector<T> v; 
    ... 
}; 

Вопрос о круговой зависимости может быть решен, если она может быть решена с помощью прямого заявления, например, для:

template <typename T> 
struct Vector{ 
    void printout(const VectorUser<T> &user); 
    ... 
}; 

вперед декларация VectorUser в сочетании с реализацией Vector<T>::printout() после объявления VectorUser т.е. в VectorUser.inl (в конце концов, никто не мог использовать вектор, не включая VectorUser.h в любом случае) дает желаемый результат:

//Vector.h: 
template <typename T> 
struct VectorUser; 


template <typename T> 
struct Vector{ 
    void printout(VectorUser<T> &user); 
    ... 
}; 

//VectorUser.h: 
template<typename T> 
struct VectorUser{...} 
}; 

template<typename T> 
void Vector<T>::printout(VectorUser<T> &user){ 
    user.printout(); 
} 

Но что, если опережающее объявление не хватает? Например:

template <typename T> 
struct Vector{ 
    VectorUser<T> user; 
    ... 
}; 

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

  1. делает Vector<T>::user указатель/ссылку, так что вперед декларация будет достаточно.

  2. расщепление Vector<T> на два класса: один базовый класс, который используется в VectorUser, а другой, полученный из него со всей функциональностью в зависимости от VectorUser.

Я бы отстаивал второе решение, но это, возможно, не всегда возможно.

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