Problem z zagnieżdżaniem klas: ClassA zawiera ClassB, ClassB zawiera wskaźnik do ClassA

0

Mam klasy Controller oraz Actions i inne. Kontroler ma w sobie Actions i inne którymi zarządza (klasy widoków, modeli, etc.). Chcę umieścić klasę Actions w kontrolerze aby zarządzał wszystkimi interakcjami. To się udaje bez problemu, to jest po prostu zwykłe wstawienie pola actions. Ale niektóre interakcje są bardziej złożone i wymagają dostępu do kontrolera aby wykonał jeszcze pewne elementy na widoku, modelu, wstrzymał bądź uruchomił jakiś wątek, którym sam zarządza. Zatem chcę też umieścić wskaźnik do kontrolera w konstruktorze Actions, żeby móc się do niego odwoływać.
Klasy wyglądają tak (zbędne funkcje zostały usunięte by nie zaciemniać):
controller.h:

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include "actions.h"

class Controller {
private:
    Actions actions = Actions::Actions(this);
}

#endif

actions.h:

#ifndef ACTIONS_H
#define ACTIONS_H

class Actions {
public:
    Actions(Controller* controller): controller(controller) {}

private:
    Controller* controller;
}

#endif

No i prosty plik main.cpp:

#include "controller.h"

int main() {
    Controller controller;

    return 0;
}

Niby prosta rzecz ale niestety otrzymuję następujące komunikaty o błędach:

In file included from controller.h:4:0,
                 from main.cpp:1:
actions.h:6:23: error: expected ‘)’ before ‘*’ token
     Actions(Controller* controller): controller(controller) {}
                       ^
actions.h:9:5: error: ‘Controller’ does not name a type
     Controller* controller;
     ^~~~~~~~~~
actions.h:10:2: error: expected ‘;’ after class definition
 }
  ^
  ;
In file included from main.cpp:1:0:
controller.h:9:2: error: expected ‘;’ after class definition
 }
  ^
  ;
controller.h:8:44: error: cannot call constructor ‘Actions::Actions’ directly [-fpermissive]
     Actions actions = Actions::Actions(this);
                                            ^
controller.h:8:44: note: for a function-style cast, remove the redundant ‘::Actions’
controller.h:8:44: error: no matching function for call to ‘Actions::Actions(Controller*)’
In file included from controller.h:4:0,
                 from main.cpp:1:
actions.h:4:7: note: candidate: constexpr Actions::Actions()
 class Actions {
       ^~~~~~~
actions.h:4:7: note:   candidate expects 0 arguments, 1 provided
actions.h:4:7: note: candidate: constexpr Actions::Actions(const Actions&)
actions.h:4:7: note:   no known conversion for argument 1 from ‘Controller*’ to ‘const Actions&’
actions.h:4:7: note: candidate: constexpr Actions::Actions(Actions&&)
actions.h:4:7: note:   no known conversion for argument 1 from ‘Controller*’ to ‘Actions&&’

Jak prawidłowo umieścić w kontrolerze obiekt Actions, by ten miał wskaźnik waśnie do tego obiektu kontrolera?

2

Poczytaj o forward declaration.

Actions actions = Actions::Actions(this);

To c++?

1

Mamy tutaj średnio groźny wariant problemu X/Y - dlaczego potrzebujesz mieć dwie zależne od siebie klasy?

Od siebie dodam tylko, że bardzo ciężko pracuje się z kodem, gdzie klasa A odpala jakąś metodę z klasy B, która znów odpala coś z klasy A - prawdopodobnie zamiast Twojego aktualnego podejścia lepiej sprawdziłby się scene stack / render stack.

0

No dobra, naniosłem kilka poprawek, teraz kod wygląda tak ale jeszcze jest kilka linijek błędów:
controller.h:

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include "actions.h"

class Controller {
private:
    Actions actions(this);
};

#endif

actions.h:

#ifndef ACTIONS_H
#define ACTIONS_H

class Controller;

class Actions {
public:
    Actions(Controller* controller): controller(controller) {}

private:
    Controller* controller;
};

#endif

Plik main.h bez zmian.

Teraz jest komunikat błędów jest jest krótszy ale jeszcze jest:

In file included from main.cpp:1:0:
controller.h:8:21: error: expected identifier before ‘this’
     Actions actions(this);
                     ^~~~
controller.h:8:21: error: expected ‘,’ or ‘...’ before ‘this’

Wiem czym jest wskaźnik this w metodach niestatycznych klas w c++. Ale nie rozumiem tego komunikatu. Jakiego identyfikatora on oczekuje przed this? Jest tylko jeden konstruktor klasy Actions i wyraźnie on oczekuje wskaźnik na obiekt typu Controller. Jak to poprawić, żeby działało bo już wyczerpałem moje pomysły.

1

Dopisz konstruktor(y) w Controller.

0

No dobra, już działa. Zrobiłem jedną poprawkę. Wskaźnik na this przekazałem poprzez listę inicjalizacyjną konstruktora zamiast wprost jako Actions actions(this); Ale na koniec niech mi ktoś napisze dlaczego to działa jeśli klasa wygląda tak:

class Controller {
public:
    Controller(): actions(this) {}

private:
    Actions actions;
};

zamiast tak:

class Controller {
private:
    Actions actions(this);
};

Tworzony jest obiekt, który wywołuje odpowiedni konstruktor. W powyższym przypadku konstruktor z argumentem na Controller*. A jednak to nie działa dopóki nie przekaże się tego przez listę inicjalizacjną.
Dlaczego nie mogę przekazać wskaźnika this bezpośrednio przy definicji pola?

--- Edit: ---
dobra nieważne. Widocznie taka specyfika języka.

1 użytkowników online, w tym zalogowanych: 0, gości: 1