PDA

View Full Version : Undefined reference to '(class name)::connectSignSlot() in moc_(class name).o



recaples
30th October 2015, 21:11
For the record: I'm pretty new to Qt, though I have a few c++ programming classes under my belt. My current class (c++, primarily) is the first exposure I've had to the Qt language.

Now, I'm making a pretty complex application that is probably a little beyond what we're expected to do for our term project. I think I have everything but this one error figured out. The error, indicated in the title, seems like it requires a very advanced knowledge of the language to even know what the deuce the connectSignSlot() function is/does. The fact that it's in a ".o" file scares me. Google has zero, yes zero, results about the error message or the function (which, I'm guessing, is part of a pretty basic library that I have no business messing about with). I can only imagine that it has something to do with the guts of the language actually doing the connecting between signals and slots. The error is in a moc_(class name).o for a custom class.

Also for the record: I was pretty careless and thrashed out a bunch of code without testing it because I was nearly certain it would work. Shame on me.

If this error can be resolved I think the application will indeed work as intended, but I am stumped. Anyone? Let me know if you need to see some code.

Unnecessary fluff: the application is a rudimentary character generator for D&D 3.5, only handling (all the following terms refer to their Dungeons and Dragons definitions) nonmagical core classes and core races (though I may drop the races down to a smaller selection). It will handle levels 1-20, no multiclassing, and it won't have any equipment to deal with. It will calculate BAB, saving throws, AC, initiative, abilities that don't have a numerical effect, and maybe a couple other things.

ChrisW67
31st October 2015, 03:01
Is the header for the class "class name" included in the HEADERS varaible of the PRO file?
Does "class name" derive from QObject and contain a Q_OBJECT macro?
Have you rerun qmake since changing either of the items above?

recaples
31st October 2015, 03:56
Yes to each of the second two questions. I don't have access to the code at the moment, so I'm not sure about whether or not it's included in the .pro but I'll figure that out as soon as I'm home.

recaples
4th November 2015, 19:24
Yes to all three, and my professor has never seen that error before. I'm stumped. I did try to start a new project and add the sources and headers to it, but it produced the same error. I will try to copy/paste the contents of the sources and headers instead of bringing over the files themselves. Maybe that'll do something.

Caolan O'Domhnaill
5th November 2015, 06:28
Try to clean, run qmake, then rebuild all. If you're using the QtCreator app right-clicking the Project name in the left panel will bring up the option to execute qmake. Make sure that this is happening by checking the output of the compiler. Then rebuild.

Assuming you ahve done this, try deleting the build directory of your project (contains your object files and intermediate build files) and then execute qmake, and rebuild. I run into this whenever I add a signal/slot combo to anything.

If those don't do it then post your files I'll see if anything is awry.

Cheers!
- Caolan O'Domhnaill

recaples
19th November 2015, 23:03
Worked on this off and on for a little while. No luck. Did all the suggestions and nothing worked. The actual error is this:


moc_ability.o:-1: error: undefined reference to `Ability::connectSignSlot()'

*I'm testing the code marker, never used it before. Source and headers to follow once I make sure I'm doing it right.*

Here's everything relevant. I didn't include the stuff for widpushbutton as it has always worked properly. Its purpose is to send a widget pointer when clicked so the stackedwidget can switch to the proper screen and it does this without problems. The "race" class isn't written up yet. All it has is an empty default constructor declaration (in the header) and definition (in the source), so I didn't include those.

ability.h:


#ifndef ABILITY_H
#define ABILITY_H

#include <QString>
#include <QObject>

class Ability : public QObject
{
Q_OBJECT

public:
Ability();
Ability(Ability&);
Ability(QString,QString,int,int);
~Ability();
Ability& operator=(int);
virtual QString getDispName();
virtual QString getDesc();
virtual int getLevel();
virtual int getVal();
virtual void setDispName(QString);
virtual void setDesc(QString);
virtual void setLevel(int);
virtual void setVal(int);
virtual void connectSignSlot();


signals:
void sendVal(int);
void sendVal(QString);
void sendLevel(int);
void sendLevel(QString);
void sendDispName(QString);
void sendDesc(QString);

public slots:
void recvDispName(QString);
void recvDesc(QString);
void recvLevel(int);
void recvVal(int);
/*void callName();
void callDesc();
void callLevel();
void callVal();
*/
private:
int level;
int val;
QString dispName;
QString desc;
};

#endif // ABILITY_H



ability.cpp:


#include "ability.h"

Ability::Ability() {

}

Ability::Ability(Ability & other) {
setDispName(other.getDispName());
setDesc(other.getDesc());
setLevel(other.getLevel());
setVal(other.getVal());
}

Ability::Ability(QString inNa,QString inDe,int inLe,int inVa) {
setDispName(inNa);
setDesc(inDe);
setLevel(inLe);
setVal(inVa);
}

Ability::~Ability() {

}

Ability& Ability::operator=(int n) {
setVal(n);

return *this;
}

QString Ability::getDispName() {
return dispName;
}

QString Ability::getDesc() {
return desc;
}

int Ability::getVal() {
return val;
}

int Ability::getLevel() {
return level;
}

void Ability::setDispName(QString in) {
dispName = in;
}

void Ability::setDesc(QString in) {
desc = in;
}

void Ability::setLevel(int n) {
level = n;
emit sendLevel(level);
}

void Ability::setVal(int n) {
val = n;
emit sendVal(val);
}

void Ability::recvDispName(QString in) {
setDispName(in);
emit sendDispName(dispName);
}

void Ability::recvDesc(QString in) {
setDesc(in);
emit sendDesc(desc);
}

void Ability::recvLevel(int in) {
setLevel(in);
emit sendLevel(QString::number(level));
}

void Ability::recvVal(int in) {
setVal(in);
emit sendVal(QString::number(val));
}



character.h:


#ifndef CHARACTER_H
#define CHARACTER_H

#include <cstdlib>
#include <ctime>
#include <map>
#include <string>
#include <vector>
#include <QApplication>
#include <QWidget>
#include <QLineEdit>
#include "ability.h"
#include "race.h"

class Character : public QObject
{
Q_OBJECT

public:
Character();
~Character();
int* roll4d6();
void reroll(int*);
bool ones(int*);
void setAC();
int getAC();
std::map<QString,Ability*> vitalStats;
std::pair<QString,Ability*> armorClass;
Race race;
void setVital(QString,int);

signals:

public slots:
void recvVital(QString,int);

private:
int AC;
};

#endif // CHARACTER_H



character.cpp:


#include "character.h"

Character::Character() {
vitalStats["STR"] = new Ability("STR", "Strength: A character's raw physical power",0,10);
vitalStats["DEX"] = new Ability("DEX", "Dexterity: A measure of both manual dexterity and how quick s/he is on his/her feet",0,10);
vitalStats["CON"] = new Ability("CON", "Constitution: A measure of physical resilience",0,10);
vitalStats["INT"] = new Ability("INT", "Intelligence: An analog to IQ, INT 10 ~ IQ 100",0,10);
vitalStats["WIS"] = new Ability("WIS", "Wisdom: A measure of street smarts and common sense",0,10);
vitalStats["CHA"] = new Ability("CHA", "Charisma: A measure of a character's likeability and personal presence",0,10);

armorClass.first = "AC";
armorClass.second = new Ability("Armor Class","A measure of how hard it is to land a hit on a character; derived from armor, magic, and dexterity",0,10);
}

Character::~Character() {

}

int* Character::roll4d6() {
srand(time(0)); rand(); rand();
int rolls[5];
for (size_t i=0; i<4; i++) {
rolls[i] = rand()%6+1;
}
return rolls;
}

void Character::setAC() {
AC = 10+vitalStats["DEX"]->getVal();
}

int Character::getAC() {
return AC;
}

void Character::setVital(QString name,int n) {
vitalStats[name]->setVal(n);
//qDebug() << QString::number(stats["STR"]);
}

void Character::recvVital(QString name,int n) {
setVital(name,n);

}



main.cpp:


#include "mainwindow.h"
#include "widpushbutton.h"
#include "character.h"
#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include <QBoxLayout>
#include <QFrame>
#include <QStackedWidget>
#include <QSpinBox>
#include <QTextEdit>
#include <QRadioButton>
#include <QLineEdit>
#include <QGridLayout>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

QStackedWidget *mainCentral = new QStackedWidget; ///< main window handling
w.setCentralWidget(mainCentral);
/**
* the individual window widgets
*/
QWidget *welcScrn = new QWidget; ///< for welcome
QWidget *rollScrn = new QWidget; ///< for roll stat-gen
QWidget *raceScrn = new QWidget; ///< for choosing player's race
QWidget *classScrn = new QWidget; ///< for choosing player's class
QWidget *charSheet = new QWidget; ///< for displaying basic character sheet


Character *merp = new Character;

/**
* adding all windows to stackedwidget
*/
mainCentral->addWidget(welcScrn);
mainCentral->addWidget(rollScrn);
mainCentral->addWidget(raceScrn);
mainCentral->addWidget(classScrn);
mainCentral->addWidget(charSheet);


//////////Welcome Scrn//////////////////////////////////////////////////


WidPushButton *rollStats = new WidPushButton(rollScrn,"Roll"); ///< button to send player to roll stat-gen
QObject::connect(rollStats,SIGNAL(widClicked(QWidg et*)),mainCentral,SLOT(setCurrentWidget(QWidget*)) );

/**
* welcome screen greetings/info
*/
QLabel *spacer1 = new QLabel("");
QLabel *welcome = new QLabel("<html><h3>Welcome to the D&D 3.5 Character Creator</h3></html>");
QLabel *welcomeSub = new QLabel("Currently only supports non-magical core classes. No multiclassing.");
QLabel *chooseGenMethod = new QLabel("How would you like to generate your stats?");
QLabel *chooseGenMethodSub = new QLabel("(this choice can only be made once per character)");

/**
* layouts for welcome screen formatting
*/
QVBoxLayout *welcScrnBones = new QVBoxLayout;
QVBoxLayout *welcScrnTop = new QVBoxLayout; welcScrnTop->setAlignment(Qt::AlignTop);
QVBoxLayout *welcScrnBot = new QVBoxLayout; welcScrnBot->setAlignment(Qt::AlignBottom);
QHBoxLayout *buttons1 = new QHBoxLayout;

buttons1->addWidget(rollStats);
buttons1->addWidget(spacer1);

QFrame *separator1 = new QFrame();
separator1->setFrameShape(QFrame::HLine);
separator1->setFrameShadow(QFrame::Sunken);

welcScrnTop->addWidget(welcome);
welcScrnTop->addWidget(welcomeSub);
welcScrnBones->addLayout(welcScrnTop);
welcScrnBones->addWidget(separator1);
welcScrnBot->addWidget(chooseGenMethod);
welcScrnBot->addWidget(chooseGenMethodSub);
welcScrnBot->addLayout(buttons1);
welcScrnBones->addLayout(welcScrnBot);

welcScrn->setLayout(welcScrnBones);


//////////Roll //////////////////////////////////////////////////


QVBoxLayout *rollBones = new QVBoxLayout;

WidPushButton *rollNextScrn = new WidPushButton(raceScrn, "Accept"); ///< button to accept stats and proceed to race selection
rollNextScrn->setToolTip("Make sure your vital statistics\nare set as you want them;\nyou will not be able to change them\nfor this character.");
QObject::connect(rollNextScrn,SIGNAL(widClicked(QW idget*)),mainCentral,SLOT(setCurrentWidget(QWidget *)));

/**
* @brief placeholderA
*
* just read it in runtime
*/
QLabel *placeholderA = new QLabel("I have code already written in c++ for rolling stats.\nThe method is to roll 4d6, or four 6-sided dice, and add\nthe highest three results (possible 3[3x1] minimum through\n18[3x6] maximum). The user is allowed one reroll, but the\nuser must take the reroll immediately after a 4d6 roll. They\ncannot wait until after all rolls have been made to retro-\nactively apply their reroll. The reroll is very specific:\nif any of the four results from rolling one of the 4d6 is a\n\"1\", the user may reroll all ones from that 4d6 until they are\nno longer 1\'s. Again, this may only happen once so the program\nmust keep track of whether or not the reroll has been used. I\nwill only implement a simplified point buy for now.");

rollBones->addWidget(placeholderA);
rollBones->addWidget(rollNextScrn);
rollScrn->setLayout(rollBones);


//////////Race Select //////////////////////////////////////////////////


QHBoxLayout *raceBones = new QHBoxLayout;
QVBoxLayout *raceList = new QVBoxLayout;

QFrame *separator3 = new QFrame;
separator3->setFrameShape(QFrame::VLine);
separator3->setFrameShadow(QFrame::Sunken);

WidPushButton *raceNextScrn = new WidPushButton(classScrn, "Accept"); ///< button to accept choice of race and proceed to class selection
QObject::connect(raceNextScrn,SIGNAL(widClicked(QW idget*)),mainCentral,SLOT(setCurrentWidget(QWidget *)));

/**
* @brief raceListItems
*
* Each race will be hard-coded with its own list of stat pluses and minuses, and its list of abilities.
* Abilities that directly affect character creation will be represented on the final Character Sheet page.
*/
QRadioButton *raceListItems[7];
raceListItems[0] = new QRadioButton("Dwarf");
raceListItems[1] = new QRadioButton("Elf");
raceListItems[2] = new QRadioButton("Gnome");
raceListItems[3] = new QRadioButton("Half-Elf");
raceListItems[4] = new QRadioButton("Half-Orc");
raceListItems[5] = new QRadioButton("Halfling");
raceListItems[6] = new QRadioButton("Human");
for (size_t i=0; i<7; i++) raceList->addWidget(raceListItems[i]);

QTextEdit *raceAbilitiesList = new QTextEdit;
raceAbilitiesList->setText("This will hold line-separated race ability descriptions, including\n\ntype (extraordinary[EX:], supernatural[SU:],and spell-like[SP:]).");

raceBones->addLayout(raceList);
raceBones->addWidget(separator3);
raceBones->addWidget(raceAbilitiesList);

raceList->addWidget(raceNextScrn);

raceScrn->setLayout(raceBones);


//////////Class Select//////////////////////////////////////////////////


QHBoxLayout *classBones = new QHBoxLayout;
QVBoxLayout *classList = new QVBoxLayout;
QHBoxLayout *levelsAccept = new QHBoxLayout;

WidPushButton *classNextScrn = new WidPushButton(charSheet, "Accept"); ///< button to accept choice of class and levels, and proceed to character sheet page
QObject::connect(classNextScrn,SIGNAL(widClicked(Q Widget*)),mainCentral,SLOT(setCurrentWidget(QWidge t*)));

QLabel *lvl = new QLabel("Levels");

QFrame *separator4 = new QFrame;
separator4->setFrameShape(QFrame::VLine);
separator4->setFrameShadow(QFrame::Sunken);

QRadioButton *classListItems[4];
classListItems[0] = new QRadioButton("Barbarian");
classListItems[1] = new QRadioButton("Fighter");
classListItems[2] = new QRadioButton("Monk");
classListItems[3] = new QRadioButton("Rogue");
for (size_t i=0; i<4; i++) classList->addWidget(classListItems[i]);

classList->addSpacing(150);
classList->addWidget(lvl);

QSpinBox *levels = new QSpinBox;
levels->setRange(1,20);
levelsAccept->addWidget(levels);
levelsAccept->addWidget(classNextScrn);
classList->addLayout(levelsAccept);

QTextEdit *classAbilitiesList = new QTextEdit;
classAbilitiesList->setText("This will hold line-separated class ability descriptions, including\n\nlevel gained and type (extraordinary[EX:],supernatural[SU:], and spell-like[SP:]).");

classBones->addLayout(classList);
classBones->addWidget(separator4);
classBones->addWidget(classAbilitiesList);

classScrn->setLayout(classBones);


to be continued...

...continued



//////////Char. Sheet //////////////////////////////////////////////////

QHBoxLayout *charBones = new QHBoxLayout;

/////Stats //////////
QVBoxLayout *statsAndSaves = new QVBoxLayout;
QWidget *statsAndSavesWidg = new QWidget; ///< for enforcing a width
statsAndSavesWidg->setFixedWidth(250);
QGridLayout *statLayout = new QGridLayout;
QGridLayout *saveLayout = new QGridLayout;

QLabel *statHeads[3]; ///< column headers for stats pane
statHeads[0] = new QLabel("Stat");
statHeads[1] = new QLabel("Score");
statHeads[2] = new QLabel("Modifier");
for (size_t i=0; i<3; i++) statLayout->addWidget(statHeads[i],0,i);

QLabel *statLabels[6];
statLabels[0] = new QLabel("STR");
statLabels[1] = new QLabel("DEX");
statLabels[2] = new QLabel("CON");
statLabels[3] = new QLabel("INT");
statLabels[4] = new QLabel("WIS");
statLabels[5] = new QLabel("CHA");
for (size_t i=0; i<6; i++) statLayout->addWidget(statLabels[i],i+1,0); ///<seed first column with labels

QLabel *statScores[6];
for (size_t i = 0; i<6; i++) {
QObject::connect(merp->vitalStats[statLabels[i]->text()],SIGNAL(sendVal(QString)),statScores[i],SLOT(setText(QString)));
}
for (size_t i = 0; i<6; i++) {
statLayout->addWidget(statScores[i],i+1,1); ///< seed second column with scores
}

QLabel *statBonus[6];
for (size_t i = 0; i<6; i++) {
statBonus[i] = new QLabel;
QString ind = statLabels[i]->text();
int mod = -5+((merp->vitalStats[ind])->getVal())/2;
if (mod>=0) {
QString text = "+";
}
text+=QString::number(mod); statBonus[i]->setText(text);
statLayout->addWidget(statBonus[i],i+1,2); ///< seed 3rd column with modifier values

}
statLayout->setAlignment(Qt::AlignLeft);



QFrame *separator5 = new QFrame;
separator5->setFrameShape(QFrame::HLine);
separator5->setFrameShadow(QFrame::Sunken);


/////Saves //////////

QLabel *saveHeads[5]; ///< column headers for saves pane
saveHeads[0] = new QLabel("Save");
saveHeads[1] = new QLabel("Total=");
saveHeads[2] = new QLabel("Base+");
saveHeads[3] = new QLabel("Stat+");
saveHeads[4] = new QLabel("Misc");
for (size_t i=0; i<5; i++) saveLayout->addWidget(saveHeads[i],0,i);

QLabel *saveLabels[3];
saveLabels[0] = new QLabel("FORT: ");
saveLabels[0]->setToolTip("Fortitude: Constitution-based");
saveLabels[1] = new QLabel("REFL: ");
saveLabels[1]->setToolTip("Reflex: Dexterity-based");
saveLabels[2] = new QLabel("WILL: ");
saveLabels[2]->setToolTip("Will: Wisdom-based");
for (size_t i=0; i<3; i++) saveLayout->addWidget(saveLabels[i],i+1,0); ///< seed save labels to 1st column

QLabel *saveBase[3];
for (size_t i=0; i<3; i++) {
saveBase[i] = new QLabel(QString::number(i));
saveLayout->addWidget(saveBase[i],i+1,2); ///< seed random-ish values as base save values
}

QLabel *saveStat[3];
saveStat[0] = new QLabel(statBonus[2]->text());
saveStat[1] = new QLabel(statBonus[1]->text());
saveStat[2] = new QLabel(statBonus[4]->text());
for (size_t i=0; i<3; i++) saveLayout->addWidget(saveStat[i],i+1,3); ///< grab the modifier from the relevant stat, seed to column 4

QLabel *saveMisc[3];
for (size_t i=0; i<3; i++) {
saveMisc[i] = new QLabel("0");
saveLayout->addWidget(saveMisc[i],i+1,4); ///< certain classes and races may provide other bonuses to saving throws, seed to column 5
}

QLabel *saveTotal[3];
for (size_t i=0; i<3; i++) {
saveTotal[i] = new QLabel("");
int tot = (saveBase[i]->text().toInt()+saveStat[i]->text().toInt()+saveMisc[i]->text().toInt());
QString finalTot;
if (tot >=0) finalTot+="+";
finalTot+=QString::number(tot);
(saveTotal[i]->text())+=QString::number(tot);
saveTotal[i]->setText(finalTot);
saveLayout->addWidget(saveTotal[i],i+1,1); ///< add total bonuses and penalties to saving throws and seed to 2nd column
}

saveLayout->setAlignment(Qt::AlignLeft);

statsAndSaves->addLayout(statLayout);
statsAndSaves->addWidget(separator5);
statsAndSaves->addLayout(saveLayout);

statsAndSavesWidg->setLayout(statsAndSaves);

charBones->addWidget(statsAndSavesWidg);

QFrame *separator6 = new QFrame;
separator6->setFrameShape(QFrame::VLine);
separator6->setFrameShadow(QFrame::Sunken);
charBones->addWidget(separator6);

/////the rest /////

QTextEdit *placeholderB = new QTextEdit;
placeholderB->setText("This will hold the rest of the information about the character. This will include Armor Class (AC) (including touch- and flatfooted-AC), initiative bonus, base attack bonus, melee and ranged attack bonus, combat maneuver bonus and defense, hit points, class abilities, number and types of feats, land speed, and vision. Maybe more if I have the time.");
charBones->addWidget(placeholderB);

charSheet->setLayout(charBones);



return a.exec();


}



Added after 5 minutes:

Sorry I had to break up main.cpp, but it was too many characters for one post.

ChrisW67
21st November 2015, 19:28
Your linker is telling you that there is no code implementing connectSignSlot(). You only have a declaration that conectSignSlot() exists (line 25 listing 2), but no actual code defining what it does.