如何实现继承自 QWidget 的 AbstractClass - Qt

How to Implement AbstractClass that Inherits from QWidget - Qt

我正在尝试使用可以从 QWidget 继承的 QT 框架在 C++ 中构建一个 class。

我试图通过在实现 QWidget 的头文件中构建 AbstractContent class 来实现这一点。然后,HorizContent继承自AbstractContent

推理

objective 是为了让多种类型的“内容”都继承自 AbstractContent,以便另一个 class 可以“热交换”它正在显示的内容类型,只需简单地重新定义单个变量。

问题

我收到当前状态代码的链接器错误。代码似乎编译得很好 - 当它进入步骤时构建失败:[build] [46/46 100% :: 137.186] Linking CXX executable spotify-qt

代码

abstractcontent.hpp
...
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QResizeEvent>

namespace Context
{
    class AbstractContent: public QWidget
    {

    Q_OBJECT

    public:
        AbstractContent(QWidget *parent) : QWidget(parent) {}

        virtual void reset() = 0;

        virtual void setCurrentlyPlaying(const lib::spt::track &track) = 0;

        virtual void setAlbum(const lib::spt::entity &albumEntity, const QPixmap &albumImage) = 0;

        // auto getCurrentlyPlaying() const -> const lib::spt::track & //I have no idea how to set this to be virtual

        virtual ~AbstractContent() {};
    };
}
horizcontent.cpp
#include "view/context/horizcontent.hpp"
#include "view/context/abstractcontent.hpp"

Context::HorizContent::HorizContent(lib::spt::api &spotify, spt::Current &current,
    const lib::cache &cache, QWidget *parent)
    : AbstractContent(parent),
    spotify(spotify),
    current(current),
    cache(cache)
{
    auto *layout = new QBoxLayout(QVBoxLayout::Direction::BottomToTop, this);
    layout->setSpacing(0);
...
}

void Context::HorizContent::onSongMenu(const QPoint &pos)
{
...
}

void Context::HorizContent::reset()
{
...
}

void Context::HorizContent::setAlbum(const lib::spt::entity &albumEntity, const QPixmap &albumImage)
{
...
}

// auto Context::HorizContent::getCurrentlyPlaying() const -> const lib::spt::track &
// {
//  return currentlyPlaying;
// }

void Context::HorizContent::setCurrentlyPlaying(const lib::spt::track &track)
{
...
}

void Context::HorizContent::resizeEvent(QResizeEvent *event)
{
    auto newWidth = event->size().width();
    auto newHeight = event->size().height();
    
    QWidget::setFixedHeight(newWidth);
    album->scaleCover(newWidth, newHeight);
}

horizcontent.hpp

...
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QResizeEvent>

namespace Context
{
    class HorizContent: public AbstractContent
    {

    public:
        HorizContent(lib::spt::api &spotify, spt::Current &current,
            const lib::cache &cache, QWidget *parent);

        void reset();

        void setCurrentlyPlaying(const lib::spt::track &track);

        void setAlbum(const lib::spt::entity &albumEntity, const QPixmap &albumImage);

        void resizeEvent(QResizeEvent *event); //For some reason I need to declare this?

    private:
        void onSongMenu(const QPoint &pos);
        ...

}

链接器错误:

[build] FAILED: spotify-qt 
[build] : && /usr/bin/c++ -g  CMakeFiles/spotify-qt.dir/spotify-qt_autogen/mocs_compilation.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/base.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/createplaylist.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/deviceselect.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/openlink.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/playlistedit.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/settings.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/setup.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/trackscachedialog.cpp.o CMakeFiles/spotify-qt.dir/src/dialog/whatsnew.cpp.o CMakeFiles/spotify-qt.dir/src/keyring/kwallet.cpp.o CMakeFiles/spotify-qt.dir/src/lib/qtpaths.cpp.o CMakeFiles/spotify-qt.dir/src/list/contributors.cpp.o CMakeFiles/spotify-qt.dir/src/list/library.cpp.o CMakeFiles/spotify-qt.dir/src/list/playlist.cpp.o CMakeFiles/spotify-qt.dir/src/list/tracks.cpp.o CMakeFiles/spotify-qt.dir/src/listitem/crash.cpp.o CMakeFiles/spotify-qt.dir/src/listitem/library.cpp.o CMakeFiles/spotify-qt.dir/src/listitem/track.cpp.o CMakeFiles/spotify-qt.dir/src/mediaplayer/mediaplayer.cpp.o CMakeFiles/spotify-qt.dir/src/mediaplayer/mediaplayerplayer.cpp.o CMakeFiles/spotify-qt.dir/src/mediaplayer/service.cpp.o CMakeFiles/spotify-qt.dir/src/menu/album.cpp.o CMakeFiles/spotify-qt.dir/src/menu/artistlinks.cpp.o CMakeFiles/spotify-qt.dir/src/menu/developermenu.cpp.o CMakeFiles/spotify-qt.dir/src/menu/mainmenu.cpp.o CMakeFiles/spotify-qt.dir/src/menu/playlist.cpp.o CMakeFiles/spotify-qt.dir/src/menu/show.cpp.o CMakeFiles/spotify-qt.dir/src/menu/track.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/about.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/application.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/base.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/interface.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/logs.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/playlists.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/spotify.cpp.o CMakeFiles/spotify-qt.dir/src/settingspage/troubleshoot.cpp.o CMakeFiles/spotify-qt.dir/src/spotify/spotify.cpp.o CMakeFiles/spotify-qt.dir/src/spotifyclient/helper.cpp.o CMakeFiles/spotify-qt.dir/src/spotifyclient/runner.cpp.o CMakeFiles/spotify-qt.dir/src/util/appinstalltype.cpp.o CMakeFiles/spotify-qt.dir/src/util/darkpalette.cpp.o CMakeFiles/spotify-qt.dir/src/util/datetime.cpp.o CMakeFiles/spotify-qt.dir/src/util/http.cpp.o CMakeFiles/spotify-qt.dir/src/util/icon.cpp.o CMakeFiles/spotify-qt.dir/src/util/image.cpp.o CMakeFiles/spotify-qt.dir/src/util/menuaction.cpp.o CMakeFiles/spotify-qt.dir/src/util/style.cpp.o CMakeFiles/spotify-qt.dir/src/util/tree.cpp.o CMakeFiles/spotify-qt.dir/src/util/url.cpp.o CMakeFiles/spotify-qt.dir/src/util/widget.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/albumslist.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/cover.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/playbutton.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/sharemenu.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/title.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/trackslist.cpp.o CMakeFiles/spotify-qt.dir/src/view/artist/view.cpp.o CMakeFiles/spotify-qt.dir/src/view/context/content.cpp.o CMakeFiles/spotify-qt.dir/src/view/context/albumcover.cpp.o CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o CMakeFiles/spotify-qt.dir/src/view/context/nowplaying.cpp.o CMakeFiles/spotify-qt.dir/src/view/context/title.cpp.o CMakeFiles/spotify-qt.dir/src/view/context/view.cpp.o CMakeFiles/spotify-qt.dir/src/view/log/application.cpp.o CMakeFiles/spotify-qt.dir/src/view/log/base.cpp.o CMakeFiles/spotify-qt.dir/src/view/log/spotify.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/albums.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/artists.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/library.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/playlists.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/searchtabtree.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/shows.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/tracks.cpp.o CMakeFiles/spotify-qt.dir/src/view/search/view.cpp.o CMakeFiles/spotify-qt.dir/src/view/sidepanel/title.cpp.o CMakeFiles/spotify-qt.dir/src/view/sidepanel/view.cpp.o CMakeFiles/spotify-qt.dir/src/view/audiofeatures.cpp.o CMakeFiles/spotify-qt.dir/src/view/cacheview.cpp.o CMakeFiles/spotify-qt.dir/src/view/configview.cpp.o CMakeFiles/spotify-qt.dir/src/view/crashes.cpp.o CMakeFiles/spotify-qt.dir/src/view/debugview.cpp.o CMakeFiles/spotify-qt.dir/src/view/lyricsview.cpp.o CMakeFiles/spotify-qt.dir/src/view/maincontent.cpp.o CMakeFiles/spotify-qt.dir/src/view/maintoolbar.cpp.o CMakeFiles/spotify-qt.dir/src/view/splashscreen.cpp.o CMakeFiles/spotify-qt.dir/src/view/systeminfoview.cpp.o CMakeFiles/spotify-qt.dir/src/view/trayicon.cpp.o CMakeFiles/spotify-qt.dir/src/widget/clickableslider.cpp.o CMakeFiles/spotify-qt.dir/src/widget/docktitle.cpp.o CMakeFiles/spotify-qt.dir/src/widget/dragarea.cpp.o CMakeFiles/spotify-qt.dir/src/widget/hiddensizegrip.cpp.o CMakeFiles/spotify-qt.dir/src/widget/loader.cpp.o CMakeFiles/spotify-qt.dir/src/widget/statusmessage.cpp.o CMakeFiles/spotify-qt.dir/src/widget/volumebutton.cpp.o CMakeFiles/spotify-qt.dir/src/main.cpp.o CMakeFiles/spotify-qt.dir/src/mainwindow.cpp.o CMakeFiles/spotify-qt.dir/spotify-qt_autogen/EWIEGA46WW/qrc_res.cpp.o -o spotify-qt  /usr/lib/libQt5Svg.so.5.15.2  lib/libspotify-qt-lib.a  /usr/lib/libQt5DBus.so.5.15.2  /usr/lib/libKF5Crash.so.5.91.0  /usr/lib/libQt5Widgets.so.5.15.2  /usr/lib/libQt5Gui.so.5.15.2  /usr/lib/libQt5Network.so.5.15.2  /usr/lib/libQt5Core.so.5.15.2 && :
[build] /usr/bin/ld: CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o: in function `Context::AbstractContent::AbstractContent(QWidget*)':
[build] /home/john/dev/spotify-qt/src/view/context/abstractcontent.hpp:28: undefined reference to `vtable for Context::AbstractContent'
[build] /usr/bin/ld: /home/john/dev/spotify-qt/src/view/context/abstractcontent.hpp:28: undefined reference to `vtable for Context::AbstractContent'
[build] /usr/bin/ld: CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o: in function `Context::AbstractContent::~AbstractContent()':
[build] /home/john/dev/spotify-qt/src/view/context/abstractcontent.hpp:36: undefined reference to `vtable for Context::AbstractContent'
[build] /usr/bin/ld: /home/john/dev/spotify-qt/src/view/context/abstractcontent.hpp:36: undefined reference to `vtable for Context::AbstractContent'
[build] /usr/bin/ld: CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o:(.data.rel.ro._ZTVN7Context12HorizContentE[_ZTVN7Context12HorizContentE]+0x10): undefined reference to `Context::AbstractContent::metaObject() const'
[build] /usr/bin/ld: CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o:(.data.rel.ro._ZTVN7Context12HorizContentE[_ZTVN7Context12HorizContentE]+0x18): undefined reference to `Context::AbstractContent::qt_metacast(char const*)'
[build] /usr/bin/ld: CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o:(.data.rel.ro._ZTVN7Context12HorizContentE[_ZTVN7Context12HorizContentE]+0x20): undefined reference to `Context::AbstractContent::qt_metacall(QMetaObject::Call, int, void**)'
[build] /usr/bin/ld: CMakeFiles/spotify-qt.dir/src/view/context/horizcontent.cpp.o:(.data.rel.ro._ZTIN7Context12HorizContentE[_ZTIN7Context12HorizContentE]+0x10): undefined reference to `typeinfo for Context::AbstractContent'
[build] collect2: error: ld returned 1 exit status

其他研究

我还查看了以前的 SO 帖子,其中包含类似 objective 的 QWidget inherit from custom QWidget and Undefined reference to vtable

我从这些帖子中了解到的要点如下:

我相信我已经实施了这两个潜在的解决方案。

各种想法:

error: no declaration matches ‘void Context::HorizContent::resizeEvent(QResizeEvent*)’

如有任何帮助或建议,我们将不胜感激! (如果我可以提供更多调试信息,请告诉我。)

在这里发布答案(感谢@aschepler 的回答)以正式结束问题。

答案是构建过程没有引入头文件。所以我不得不添加以下行:

target_sources(${PROJECT_NAME} PRIVATE
    ...
    ${CMAKE_CURRENT_SOURCE_DIR}/abstractcontent.hpp
    ...

CMakeLists.txt