Как использовать поле класса из внешней функции?

У меня есть класс кнопки Button, в котором я создал указатель на функцию, которая должна исполняться по нажатию на кнопку. Эдакий коллбэк, задаваемый извне.
В определенном месте кода, мне нужно использовать в этом коллбэке текст, введенный пользователем в текстовое поле, что происходит в определенном классе. Но я получаю ошибку login.cpp|80|undefined reference to Login::tf

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

Вот код класса Button ниже; То, что я посчитал маловажным убрано, но если что, полный код лежит на github:
(если это возможно, я бы хотел оставить интерфейс этого класса без изменений, так как он много где используется)

///Класс кнопки. Обрабатывает клик, выполняет скормленную ему функцию реакции на него.
class Button : public AbstractUIElement
{
/*стандартный цвет кнопки, цвет при вхождении курсора в область кнопки*/

public:
    void (*onClick)(StateBasedGame*, SDL_Event*);  // функция-обработчик клика

    /// можно создать кнопку, не устанавливая функцию, которую она будет выполнять
    Button(char* myText) {/*...*/}

    /// инициализация кнопки функцией, которую она выполняет
    Button( void (*callback)(StateBasedGame* e, SDL_Event* g), char* myText )
    {
       onClick = callback;
       /*...*/
    }

    void update(StateBasedGame* g, SDL_Event* e)
    {
        if( e->type == SDL_MOUSEMOTION || e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEBUTTONUP )
        {
            int x, y;
            SDL_GetMouseState( &x, &y );

            bool inside = true;

            if( x < bounds.x )
            {
                inside = false;
            }
            else if( x > bounds.x + bounds.w )
            {
                inside = false;
            }
            else if( y < bounds.y )
            {
                inside = false;
            }
            else if( y > bounds.y + bounds.h )
            {
                inside = false;
            }

            if( !inside )
            {
                color = backup_color;
            }
            else
            {
                switch( e->type )
                {
                    case SDL_MOUSEMOTION:
                        color = ACTIVE_COLOR;
                    break;

                    case SDL_MOUSEBUTTONDOWN:
                         color = CLICK_COLOR;
                         onClick(g, e);
                    break;
                    case SDL_MOUSEBUTTONUP:
                         color = CLICK_COLOR;
                         onClick(g, e);
                    break;
                }
            }
        }
    }

    void setCallback (void (*callback)(StateBasedGame* e, SDL_Event* g))
    {
        this->onClick = callback;
    }
};

А вот класс, данные которого должна использовать кнопка. В TextField tf вводится имя, которое по нажатию на кнопку должно записаться в глобальную структуру, отвечающую за пользователей в текущей сессии. Код выложен практически полностью, но вот на всякий случай ссылка на него в том же проекте.

#ifndef LOGIN
#define LOGIN

using namespace std;

    static void loginOnClick(StateBasedGame* g , SDL_Event* e);

class Login : public GameState
{
    SDL_Event event;
    SDL_Surface* screen;
    Button* back_button;
    Label* text;
public:
    static TextField tf;

    void init( SDL_Surface* display, StateBasedGame* g )
    {
        screen = display;
        back_button = new Button(loginOnClick, "Продолжить");
        back_button->bounds.x = (display->w - back_button->bounds.w)/2;
        back_button->bounds.y = display->h - back_button->bounds.h - 50;

        text = new Label("Введите имя:");
        text->bounds.w = 300;
        text->bounds.x = (screen->w - text->bounds.w)/2;
        text->bounds.y = screen->h/2-50;

        tf.bounds.w = 300;
        tf.bounds.x = (screen->w - tf.bounds.w)/2;
        tf.bounds.y = screen->h/2;
    }

    void update( StateBasedGame* g, int delta )
    {
        if(SDL_PollEvent(&event)) {
            if(event.type == SDL_QUIT) g->exit();
            tf.update(event);
        }
        back_button->update(g, &event);
    }

    void render( SDL_Surface* display )
    {
        back_button->render(display);
        text->render(display);
        tf.render(display);
    }

    SDL_Event* pollEvent( void )
    {
        return &event;
    }

    SDL_Surface* getScreen()
    {
        return screen;
    }

    ~Login()
    {
        delete back_button;
        delete text;
    }
};

#ifndef LOGIN_ON_CLICK
#define LOGIN_ON_CLICK
    static void loginOnClick(StateBasedGame* g , SDL_Event* e)
    {
        Player* player = new Player((Login::tf).text);
        current_session.players.push_back(player);
        current_session.current_player = player;
        g->switchState(states::main_menu);
    }
#endif // LOGIN_ON_CLICK

#endif // LOGIN

Я пробовал следующее:

  • создавать функцию статической до объявления класса, но тогда она не знает о его существовании, и как следствие не может обратиться к его членам
  • создавать её и статической и не статической внутри класса. Позже нашёл объяснение в интернете, что это так работать не будет. Там есть пример рабочего синтаксиса, но он, на сколько я понял, будет привязан к одному конкретному классу, а мне нужен подход, который позволит использовать подобные конструкции в будущем и для других классов - универсальная кнопка, какой она до сих пор и была, пока не потребовался доступ к членам класса-пользователя кнопки.
  • пробовал пользоваться лямбда-выражением вместо создания функции, и передачи её указателя позже, но запутался в синтаксисе, и словил столько ошибок, что оставил идею, и вернулся к ранее работавшему варианту с отдельной функцией. Сама идея реализовать функцию прямо на месте присвоения, как анонимный объект в java, мне нравится.

Буду рад, если поможете починить мои кнопки, и объясните, что я делаю не так. Заранее спасибо.


Ответы (0 шт):