Чтобы разрешить циклические зависимости в C ++, для * изобретены *1001* форвардные объявления.
Каким-то образом OP попытался, но неправильно.
Так, если
class translation2d
необходимо class rotation2d
и
class rotation2d
необходимо class translation2d
второй должен быть объявлен вперед перед первым.
struct rotation2d; // forward declaration -> incomplete type
struct translation2d {
void doSomethingWith(rotation2d rot);
};
struct rotation2d {
void doSomethingWith(translation2d trans);
};
Демонстрация в Compiler Explorer
Предварительное объявление делает неполного типа . Неполные типы ограничены относительно того, что можно сделать с ними.
Ни размер, ни содержимое неполного типа не известны. Следовательно, компилятор запрещает все, где это необходимо, например,
- выделение памяти (т.е. создание из нее переменной или члена-переменной)
- доступ к содержимому (т.е. чтение / запись переменные-члены или вызов функций-членов).
Допускается использование неполных типов для
- указателей и ссылок (с любой квалификацией)
- параметров объявления функций.
Я должен признать, что не знал о последнем, но обнаружил: SO: неполные типы в качестве параметров функции и возвращаемых значений для моего освещения.
Обратите внимание, что параметры функции декларации могут быть неполными, но не параметры функции определения . Следовательно, вторая часть исправления состоит в том, чтобы сделать функции non- встроенными, если в них требуются неполные типы.
struct rotation2d; // forward declaration -> incomplete type
struct translation2d {
void doSomethingWith(rotation2d rot);
};
struct rotation2d {
void doSomethingWith(translation2d trans)
{
trans; // will be processed somehow
}
};
// now both types are complete
void translation2d::doSomethingWith(rotation2d rot)
{
rot; // will be processed somehow
}
Демонстрация в Compiler Explorer
Фиксированный и завершенный пример кода OP:
#include <iostream>
#include <limits>
#include <cmath>
class rotation2d; // forward declaration
class translation2d
{
public:
double x;
double y;
translation2d()
{
x=0;
y=0;
}
translation2d(double x, double y): x(x), y(y) { }
translation2d rotateBy(rotation2d rotation); //issue here fixed
};
double kEpsilon = 0.000000009;
class rotation2d
{
public:
double cosAngle;
double sinAngle;
public:
rotation2d()
{
cosAngle=1;
sinAngle=0;
}
rotation2d(const translation2d& direction, bool norm)
{
cosAngle=direction.x;
sinAngle=direction.y;
if(norm)
normalize();
}
double cosM()
{
return cosAngle;
}
double sinM()
{
return sinAngle;
}
double tanM()
{
if(abs(cosAngle)<kEpsilon)
{
if(sinAngle>=0.0)
return std::numeric_limits<double>::infinity();
else
return -1*std::numeric_limits<double>::infinity();
}
return sinAngle/cosAngle;
}
void normalize()
{
const double len = std::sqrt(cosAngle * cosAngle + sinAngle * sinAngle);
cosAngle /= len; sinAngle /= len;
}
};
// both types complete now -> circular dependency resolved
translation2d translation2d::rotateBy(rotation2d rotation)
{
translation2d copy=*this;
copy=translation2d(x*rotation.cosM()-y*rotation.sinM(), x*rotation.sinM() + y*rotation.cosM());
return copy;
}
int main()
{
translation2d t(1.0, 2.0);
rotation2d r(translation2d(0.0, 1.0), false);
translation2d tR = t.rotateBy(r);
std::cout << "tR: (" << tR.x << ", " << tR.y << ")\n";
}
Вывод:
tR: (-2, 1)
Live Demo на колиру