不完整类型嵌套名称说明符 JUCE
Incomplete Type InNested Name Specifier JUCE
我在尝试使用 'WindowList' class 管理我的 windows 时遇到循环依赖问题。当我想用下面的 closeButtonPressed 代码关闭 window 时,我需要从 windowList 文件中删除该对象,但是我在 WindowList 文件中包含了 WindowSetter。以前的此类错误可以通过前向声明解决,但是我不确定如何解决这个错误。有什么建议吗?
(完整代码可以在这里查看:https://gist.github.com/anonymous/7d43c6d5b2cf1fef618be9f75077ad0c)
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "WindowList.h"
class WindowList;
class WindowSetter : public DialogWindow
{
public:
WindowSetter (const String& title,
Component* content,
bool shouldBeResizeable,
int initWidth, int initHeight,
int minWidth, int minHeight,
int maxWidth, int maxHeight)
: DialogWindow (title, Colours::white, true, true),
owner (this)
{
setUsingNativeTitleBar (true);
setResizable (true, true);
setResizeLimits (minWidth, minHeight, maxWidth, maxHeight);
setContentOwned (content, false);
setVisible (true);
}
~WindowSetter()
{
}
void closeButtonPressed() override
{
WindowList::getWindowList(); // ERROR: Incomplete type 'WindowList' named in nested name specifier
owner = nullptr;
}
bool escapeKeyPressed() override
{
return true;
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowSetter)
ScopedPointer<Component> owner;
};
编辑:添加了导致错误的文件的完整代码和错误日志截图
让我们从假想的编译器的角度看一下您的代码,看看到底发生了什么...
// NOTE: we're in WindowSetter.h
#include "WindowList.h"
没问题,让我们看一下该文件并将其包含在此处...
// NOTE: we're in WindowList.h
#include "WindowSetter.h"
好的,我们去看看...
// NOTE: we're back in WindowSetter.h
#include "WindowList.h"
但是……我就是这么做的。天哪,我陷入了无限循环。帮助!
KABOOM
编译器无法包含您要求的 header,因为它们在无限循环中相互需要。您需要以这种递归方式不包括 header 来打破这个循环。
您已经知道的前向声明对此很有用。原因是因为它们可以通知编译器有关类型名称的信息,而无需包含 header。如果编译器只需要知道类型名称,而不需要知道其他任何东西(例如大小),那就太好了。
你在这里遇到的问题,撇开体系结构问题,是你在这里 WindowSetter
内部使用 WindowList
的内部结构:
WindowList::getWindowList(); // ERROR: Incomplete type 'WindowList' named in nested name specifier
这可能就是您最终将 header 放在首位的原因;如果你不这样做,它会给你一个类似的错误。
要解决此问题,您可以将成员函数 closeButtonPressed()
的定义移到 header 文件之外并移到 .cpp 文件中。为了保持一致性,您可能也想移动其他功能(个人意见问题)。
完成后,您将不再在 WindowSetter.h
中使用 WindowList
的详细信息,因此可以停止包含它。
这将解决您的问题,除非其他地方隐藏了其他循环依赖项(我没有全部阅读)。
OMGtechy 的回复解决了您提出的问题,但我想推荐一种不同的设计:
- 无需担心循环依赖
- 是更惯用的 JUCE 代码。
这里的设计将所有东西紧密地结合在一起。解决问题的更 JUCE-y 方法是使用 ChangeBroadcaster
/ ChangeListener
类 来消除紧密耦合。当您将 WindowSetter
添加到您的 WindowList
时,还要订阅其更改消息。当用户单击关闭按钮时,WindowSetter
设置一个布尔值并提醒任何收听它的人它已更新。
在草图中,它看起来像
class WindowSetter : public DialogWindow
, public ChangeBroadcaster
{
public:
WindowSetter( /*(etc...)*/)
: DialogWindow(...)
, owner(this)
, wantsToClose(false)
{
// etc
}
void closeButtonPressed() override
{
wantsToClose = true;
// notify observers that we've changed.
sendChangeMessage();
}
bool windowWantsToClose() const
{
return wantstoClose;
}
private:
bool wantsToClose;
};
class WindowList : public ChangeListener
{
void addWindowSetterToList(WindowSetter* wnd)
{
wnd->addChangeListener(this)
windows.addIfNotAlreadyThere(wnd);
}
void changeListenerCallback(ChangeBroadcaster* src) override
{
// cast from the ChangeBroadcaster base class to our WindowSetter class.
WindowSetter* wnd = dynamic_cast<WindowSetter*>(src);
if (nullptr != wnd)
{
// if we contain the object, and the object wants to be closed...
if (windows.contains(wnd) && wnd->windowWantsToClose())
{
// get rid of it.
windows.remove(wnd);
}
}
}
};
你会看到这种设计在 JUCE 代码库中几乎无处不在。
我在尝试使用 'WindowList' class 管理我的 windows 时遇到循环依赖问题。当我想用下面的 closeButtonPressed 代码关闭 window 时,我需要从 windowList 文件中删除该对象,但是我在 WindowList 文件中包含了 WindowSetter。以前的此类错误可以通过前向声明解决,但是我不确定如何解决这个错误。有什么建议吗? (完整代码可以在这里查看:https://gist.github.com/anonymous/7d43c6d5b2cf1fef618be9f75077ad0c)
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "WindowList.h"
class WindowList;
class WindowSetter : public DialogWindow
{
public:
WindowSetter (const String& title,
Component* content,
bool shouldBeResizeable,
int initWidth, int initHeight,
int minWidth, int minHeight,
int maxWidth, int maxHeight)
: DialogWindow (title, Colours::white, true, true),
owner (this)
{
setUsingNativeTitleBar (true);
setResizable (true, true);
setResizeLimits (minWidth, minHeight, maxWidth, maxHeight);
setContentOwned (content, false);
setVisible (true);
}
~WindowSetter()
{
}
void closeButtonPressed() override
{
WindowList::getWindowList(); // ERROR: Incomplete type 'WindowList' named in nested name specifier
owner = nullptr;
}
bool escapeKeyPressed() override
{
return true;
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowSetter)
ScopedPointer<Component> owner;
};
编辑:添加了导致错误的文件的完整代码和错误日志截图
让我们从假想的编译器的角度看一下您的代码,看看到底发生了什么...
// NOTE: we're in WindowSetter.h
#include "WindowList.h"
没问题,让我们看一下该文件并将其包含在此处...
// NOTE: we're in WindowList.h
#include "WindowSetter.h"
好的,我们去看看...
// NOTE: we're back in WindowSetter.h
#include "WindowList.h"
但是……我就是这么做的。天哪,我陷入了无限循环。帮助!
KABOOM
编译器无法包含您要求的 header,因为它们在无限循环中相互需要。您需要以这种递归方式不包括 header 来打破这个循环。
您已经知道的前向声明对此很有用。原因是因为它们可以通知编译器有关类型名称的信息,而无需包含 header。如果编译器只需要知道类型名称,而不需要知道其他任何东西(例如大小),那就太好了。
你在这里遇到的问题,撇开体系结构问题,是你在这里 WindowSetter
内部使用 WindowList
的内部结构:
WindowList::getWindowList(); // ERROR: Incomplete type 'WindowList' named in nested name specifier
这可能就是您最终将 header 放在首位的原因;如果你不这样做,它会给你一个类似的错误。
要解决此问题,您可以将成员函数 closeButtonPressed()
的定义移到 header 文件之外并移到 .cpp 文件中。为了保持一致性,您可能也想移动其他功能(个人意见问题)。
完成后,您将不再在 WindowSetter.h
中使用 WindowList
的详细信息,因此可以停止包含它。
这将解决您的问题,除非其他地方隐藏了其他循环依赖项(我没有全部阅读)。
OMGtechy 的回复解决了您提出的问题,但我想推荐一种不同的设计:
- 无需担心循环依赖
- 是更惯用的 JUCE 代码。
这里的设计将所有东西紧密地结合在一起。解决问题的更 JUCE-y 方法是使用 ChangeBroadcaster
/ ChangeListener
类 来消除紧密耦合。当您将 WindowSetter
添加到您的 WindowList
时,还要订阅其更改消息。当用户单击关闭按钮时,WindowSetter
设置一个布尔值并提醒任何收听它的人它已更新。
在草图中,它看起来像
class WindowSetter : public DialogWindow
, public ChangeBroadcaster
{
public:
WindowSetter( /*(etc...)*/)
: DialogWindow(...)
, owner(this)
, wantsToClose(false)
{
// etc
}
void closeButtonPressed() override
{
wantsToClose = true;
// notify observers that we've changed.
sendChangeMessage();
}
bool windowWantsToClose() const
{
return wantstoClose;
}
private:
bool wantsToClose;
};
class WindowList : public ChangeListener
{
void addWindowSetterToList(WindowSetter* wnd)
{
wnd->addChangeListener(this)
windows.addIfNotAlreadyThere(wnd);
}
void changeListenerCallback(ChangeBroadcaster* src) override
{
// cast from the ChangeBroadcaster base class to our WindowSetter class.
WindowSetter* wnd = dynamic_cast<WindowSetter*>(src);
if (nullptr != wnd)
{
// if we contain the object, and the object wants to be closed...
if (windows.contains(wnd) && wnd->windowWantsToClose())
{
// get rid of it.
windows.remove(wnd);
}
}
}
};
你会看到这种设计在 JUCE 代码库中几乎无处不在。