'MainWindow' does not name a type
-
hello guys ,
i have a class named MyClass like this :#ifndef MYCLASS_H #define MYCLASS_H #include <QObject> #include "mainwindow.h" class MyClass : public QObject { Q_OBJECT public: explicit MyClass (QObject *parent = 0); static MainWindow * m_main ; static void NotifySystem(); public slots: }; #endif // MYCLASS_H
when i include the Myclass.h in my MainWindow.h the following error appears :
error: 'MainWindow' does not name a type MainWindow * m_main ; ^
it's something like Dependency Loop how can i use the MainWindow in other classes ?
-
Yes, it's a dependency cycle.
There is no single answer. The general rule is you model your app like a tree - the top level class instantiates some children, these instantiate some more and so on. The rule is that you never include from above you co that you don't turn a tree into a graph with cycles.
MainWindow is usually kinda near or at the top so there shouldn't be (m)any things including it.When you have a class included in mainwindow and you want to access mainwindow from that class it usually is a sign of bad design. The use of
static
there only strengthens that belief.
The tree-like design is that mainwindow instantiates a child (a dialog, a panel, a manager or whatever), runs some methods on it and retrieves some data from it. The child instance should never know about a mainwindow or any parent for that matter. Everything should look downward.What's your particular use case here? Maybe we can help you find the right design.
-
Yes, it's a dependency cycle.
There is no single answer. The general rule is you model your app like a tree - the top level class instantiates some children, these instantiate some more and so on. The rule is that you never include from above you co that you don't turn a tree into a graph with cycles.
MainWindow is usually kinda near or at the top so there shouldn't be (m)any things including it.When you have a class included in mainwindow and you want to access mainwindow from that class it usually is a sign of bad design. The use of
static
there only strengthens that belief.
The tree-like design is that mainwindow instantiates a child (a dialog, a panel, a manager or whatever), runs some methods on it and retrieves some data from it. The child instance should never know about a mainwindow or any parent for that matter. Everything should look downward.What's your particular use case here? Maybe we can help you find the right design.
@Chris-Kawa thanks for your reply ,
i have a winapi class which has a CALLBACK function and it should be static (windows rules) in this function i need to update some controls based on callback result , so because callback is static i cant use SIGNAL/SLOT and i have to pass the mainwindows somehow to update it from static method , so how can i implement that without a bad design :D thanks . -
i have used the
forward declaration
to fix the error but it's not standard i'm looking for true way not hacky way@MrOplus said in 'MainWindow' does not name a type:
i have used the
forward declaration
to fix the error but it's not standard i'm looking for true way not hacky wayForward declaration is not only standard but something you should strive for. It will speed up your builds tremendously. I try to almost never include things in my headers if I can avoid it.
The second thing here is you are breaking the rules of OOP if you have interdependent objects like that. Having an object use your main window is quite common but having you main window need that same object #include'd as well is quite abnormal.
So like @Chris-Kawa said it is definitely bad class design/oop. I would fix the design but barring that forward declaration will fix it. You should use forward declaration as much as possible in C++ though. The build speed benefits alone are worth it. :)
Oh and another potential fix is to not include myclass in your mainwindow.h. You can either forward declare there, or better yet just include it in the cpp. If your mainwindow relies on MyClass and MyClass relies on MainWindow that is the bad design part. An
Apple
doesn't need to know anything about aWorm
but theWorm
needs to know about theApple
to eat it. So includingWorm
inApple
would be bad since they aren't really related even though one can use/work with the other. -
For C like apis (WinApi being an example) you usually create a wrapper class. That wrapper's sole purpose is to wrap the foreign api. It should not mangle with MainWindow. It can emit signals that MainWindow chooses to connect to. This way only MainWindow (higher in the tree) knows about a wrapper (includes it). A dumb wrapper can look like this:
class WinAPiWrapper : public QObject { Q_OBJECT public: WinAPiWrapper(QObject* parent = nullptr) : QObject(parent) { instance = this; } ~WinAPiWrapper() { instance = nullptr; } public slots: void CallSomeWinapi(int param, int param2) { WinApiFunc(param, param2, WinapiCallback); } signals: void SomeWinapiFinished(int ret_param) const; private: static void WinapiCallback(int ret_param) { if (instance) emit instance->SomeWinapiFinished(ret_param); } static WinAPiWrapper* instance; };
Of course it doesn't follow the rules of a good singleton for brevity. Make necessary adjustments.
Some callbacks are nicer than others. The nicer ones have a
void*
or similar pointer for user data. This is often used to pass thethis
pointer to them and get it back in the callback. With such callbacks you don't even need a singleton solution:class WinAPiWrapper : public QObject { Q_OBJECT public: WinAPiWrapper(QObject* parent = nullptr) : QObject(parent) {} public slots: void CallSomeWinapi(int param, int param2) { WinApiFunc(param, param2, WinapiCallback, this); //assuming the last param is the void* user data } signals: void SomeWinapiFinished(int ret_param) const; private: static void WinapiCallback(int ret_param, void* user_data) { WinAPiWrapper* instance = reinterpret_cast<WinAPiWrapper*>(user_data); //get back the instance pointer from user data emit instance->SomeWinapiFinished(ret_param); } };