Как переслать объявить функцию-член класса для использования в другом классе?

Я сделал два одинаковых класса X и Y, указав друг на друга. См. Код ниже для X.h, Y.h идентичен всем X и Y, замененным. Этот код дает, однако, ошибку в моем методе Connect (ошибка C2027: использование undefined типа "Y" ). В X.h у меня есть forward, объявленный классом Y, но он не знает, что Y имеет метод с именем SetXPointer. Поэтому мне также нужно переслать декларировать этот метод, исправить?

Если я попытаюсь это сделать (добавив строку Y:: SetXPointer (X * pX_in); в классе строк Y;), я получаю ошибку компилятора C2761: 'void Y:: SetXPointer (X *)': не разрешено повторное использование функции члена. Есть ли способ использовать общедоступный метод класса Y в классе X?

// X.h

#pragma once

#include "Y.h"

// Forward declaration
class Y;

class X
{
public:
    X(void) : data(24) {};
    ~X(void) {};
    int GetData() { return data; }
    void SetYPointer(Y* pY_in) { pY = pY_in; }
    Y* GetYPointer() { return pY; }
    void Connect(Y* Y_in) { pY = Y_in; Y_in->SetXPointer(this); }
private:
    int data;
    Y *pY;
};

Ответ 1

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

class Y;
class X {
  …
  void Connect(Y* Y_in);
  …
};
class Y {
  …
  void Connect(X* X_in);
  …
};
inline void X::Connect(Y* Y_in) {
  pY = Y_in;
  Y_in->SetXPointer(this);
}
inline void Y::Connect(X* X_in) {
  pX = X_in;
  X_in->SetXPointer(this);
}

Таким образом, полная информация о том, как объекты класса будут выложены в памяти, доступна к моменту реализации метода Connect. И как метод в классе класса и объявленный метод inline будут одинаковыми, так же, как и производительность.

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

Ответ 2

Единственный способ сделать это, если оба класса нуждаются в полном типе в своих методах, заключается в том, чтобы разделить реализацию на файл реализации.

Ответ 3

Если вы намерены совместно использовать большие части реализации между X и Y, вы можете сделать это с помощью шаблона. Одним из примеров является следующее:

template<bool isX> class XY
{
public:
  typedef XY<!isX> YX; // This is the opposite type to the current one.
  XY(void) : data(24) {};
  ~XY(void) {};
  int GetData() { return data; }
  void SetPointer(YX* pYX_in) { pYX = pYX_in; }
  YX* GetPointer() { return pYX; }
  void Connect(YX* YX_in) { pYX = YX_in; YX_in->SetPointer(this); }
private:
  int data;
  YX *pYX;
};

typedef XY<true> X;
typedef XY<false> Y;

Поскольку методы шаблона только создаются при использовании, вы избегаете описанной выше проблемы, так как к моменту их создания оба типа известны. Если у вас позже есть различия между X и Y, вы можете использовать наследование вместо typedef.

Ответ 4

Вы можете поместить класс B в класс A

using namespace std;

class A
{
        public:
        void run()
        {
                B b("hi");
                b.run(this);
        }

        void print(string &msg) { cout << msg << endl; }

        private:
        class B
        {
                public:
                B(string m) : msg(m) {}
                void run(A *a) { a->print(msg); }

                private:
                string msg;
        };
};

int main()
{
        A a;
        a.run();
        return 0;
}