Home > Net >  How to Implement AbstractClass that Inherits from QWidget - Qt
How to Implement AbstractClass that Inherits from QWidget - Qt

Time:03-04

I'm trying to build a class in C using the QT framework that can inherit from QWidget.

I am attempting to do this by building an AbstractContent class in a header file that implements QWidget. Then, HorizContent inherits from AbstractContent.

Reasoning

The objective is to have multiple types of "content" all inherit from AbstractContent so that another class can "hot swap" the type of content it is displaying by simply redefining a single variable.

Issue

I am getting Linker errors with the code in it's current state. The code seems to compile just fine - the build fails when it gets to step: [build] [46/46 100% :: 137.186] Linking CXX executable spotify-qt

Code

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);
        ...

}

Linker Errors:

[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

Other Research

I have also taken a look at previous SO posts with similar objectives like QWidget inherit from custom QWidget and Undefined reference to vtable

The takeaways I understood from those posts are the following:

  • Ensure that the methods in the abstract class are marked as virtual <method> = 0
  • Ensure that the abstract class has a destructor

I believe I have both of these potentional solutions implemented.

Assorted Thoughts:

  • I wonder if needing to declare resizeEvent in the child class could be contributing to the issue? For some reason, when I dont include resizeEvent in the public declarations in HorizContent the build failes with:
error: no declaration matches ‘void Context::HorizContent::resizeEvent(QResizeEvent*)’
  • I would think that because resizeEventi s already a member of QWidget which is inherited by AbstractContent, it should already be defined?

Any assistance or suggestions would be most appreciated! (If there is any more debug info I can provide please let me know.)

CodePudding user response:

Posting the answer (thanks to @aschepler for the answer) here to officially close out the question.

The answer was that the build process wasn't bringing the header file in. So I had to add the line:

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

in CMakeLists.txt

  • Related