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 ¤t,
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 ¤t,
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 includeresizeEvent
in the public declarations inHorizContent
the build failes with:
error: no declaration matches ‘void Context::HorizContent::resizeEvent(QResizeEvent*)’
- I would think that because
resizeEvent
i s already a member ofQWidget
which is inherited byAbstractContent
, 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