Ineritance, Using Base class constructor. LNK2019 error

I am trying to create a few subclasses which all use the base class constructor, according to my book this is all fine and dandy by using the "using Baseclass::Baseclass", this doesnt work for me.

1
2
3
4
5
6
7
8
9
10
11
class Monster {
public:
	Monster(char[], char[], char[], int); //The constructor, and its implemented.
	etc..
};

class Human : public Monster {
public:
	using Monster::Monster; // This should be enough to use the above constructor?
	etc..
};


Yet, i recieve this error:
error LNK2019: unresolved external symbol "public: __thiscall Human::Human(char * const,char * const,char * const,int)"


Why is this? Does doing it this way create const pointers somehow? The constructor works fine with Monster, i am using the same calls, just changed to create Human instead of Monster. All files are included where they should, monster and human are declared in the same header.
Can you provide a minimal example that reproduces your issue? It is near impossible to help when you have omitted so much code.

Also, be sure you're using the latest Visual Studio IDE so that you have the latest C++11 support - Visual Studio has incomplete support for C++11 and C++14 but it slowly catching up.
Last edited on
Calling for the creation of a Monster/Human:
1
2
db.add(Monster("Kitten", "Cat", "Hunter", 2));
db.add(Human("Hodor", "Hodor", "Hodor", 5));


Declaration of the classes:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Monster {
public:
	Monster(char[], char[], char[], int);
	std::string name, race, job;
	int health;
	virtual void print() { std::cout << name << " is a simple monster surviving as a " << job << " with only " << health << "health points." << std::endl; }
};

class Human : public Monster {
public:
	using Monster::Monster;
	void print() { std::cout << name << " is walking this earth as a proud human " << job << " with " << health << " health points. " << std::endl; }
};


Implemented constructor:
1
2
3
4
5
6
7
8
9
10
Monster::Monster(char n[], char r[], char j[], int h){
	std::stringstream ssN, ssR, ssJ;
	ssN << n;
	name = ssN.str();
	ssR << r;
	race = ssR.str();
	ssJ << j;
	job = ssJ.str();
	health = h;
}


That's all that has to do with the classes and constructors.
Why are you passing parameters via C character arrays instead of as std::string if you are using std::string anyway? And do you realize you don't need to use stringstreams to convert here?

This is what you should do:
1
2
3
4
5
6
7
Monster::Monster(std::string const &n, std::string const &r, std::string const &j, int h)
: name{n}
, race{r}
, job{j}
, health{h}
{
}
Last edited on
I really don't know, the teacher have had earlier use of chars and stuff, and first error was something with chars and i just went with it and haven't gone back since it worked, and converting between different types is such a hassle.

That fixed the linking error, but it still doesn't work, console says
error C2660: 'Human::Human' : function does not take 4 arguments

and hovering above the error it says there is no constructor matching the char, char,char, int stuff.
Your compiler might not support inheriting constructors - you'll have to manually implement a constructor for Human which calls the Monster constructor.
1
2
3
4
Human::Human(std::string const &n, std::string const &r, std::string const &j, int h)
: Monster(n, r, j, h)
{
}
Last edited on
Strange, i am using Visual Studio 2013, not Express, got it via dreamspark.
Anyways, that works, just running into new problems. Since a function that prints the print() takes a Monster, it uses the Monster print(). And passing the race both as object and text, seems like he hasn't had the test program working for the second part of the task.
Sabomoth wrote:
Since a function that prints the print() takes a Monster, it uses the Monster print().
I don't believe you. That function is virtual and is correctly overridden. Are you sure you're not experiencing splicing? Make sure your copy and move constructors are private or deleted.
1
2
3
4
MonsterDB db;
db.add(Monster("Kitten", "Cat", "Hunter", 2));
db.add(Human("Hodor", "Hodor", "Hodor", 5));
db.printList();

Their classes have already been posted, and you know they are correct.

 
void MonsterDB::add(const Monster& entry){ first = new MonsterDBNode(first, entry); counter++; }

And that class:
1
2
3
4
5
6
class MonsterDBNode{
public:
	MonsterDBNode(MonsterDBNode *n, Monster const &d) : next(n), data(d) {};
	Monster data;
	MonsterDBNode *next;
};


And lastly the function:
1
2
3
4
5
6
void MonsterDB::printList(){
	for (MonsterDBNode *p = first; p; p = p->next)
	{
		p->data.print();
	}
}


Is that splicing/slicing you talk about done in the data(d) part of the MonsterDBNode constructor? Because that's the only place i can think of? But it just hands over the reference?
Make data a non-value type and you should be fine.
I changed it to a reference type and fixed one of the errors that caused, but stuck on the second, which is a return function. I cant return a pointer from a const pointer, and the thing is i cant change that function to return a const instead, since its part of the task.

1
2
3
4
5
6
7
Monster* MonsterDB::find(const std::string& name){
	for (MonsterDBNode *p = first; p; p = p->next)
	{
		if (p->data.name == name) return &p->data;
	}
	return NULL;
}

error C2440: 'return' : cannot convert from 'const Monster *' to 'Monster *'


Did you make data const?
Yes, otherwise it wouldn't work to change it to a reference or a pointer. It receives a const Monster reference, cant put that in something that isn't const?
MonsterDB::find will need to change, in that case. If you're building up a linked list of nodes that contain const data then it can't be expected that you can retrieve non-const data.

If you ask me, the prototype should be:
const Monster* MonsterDB::find(const std::string& name) const
Last edited on
Probably, much of my agony comes from such problems. Reading on the course forum i actually have two other classmates stuck on the same problem with splicing(printing from subclasses not working). Maybe its a design flaw from the teacher, but cant really do anything about it unless he says so.

This is all the functions we need in the program. You can see the const Monster being added, and the find(), etc.
1
2
3
4
5
6
7
8
9
10
void MonsterDB::add(const Monster& entry)
Monster* MonsterDB::find(const std::string& name)
void MonsterDB::remove(Monster *entry)
void MonsterDB::flushList()
int MonsterDB::size()
void MonsterDB::print(Monster *entry)
void MonsterDB::printList()

MonsterDB::MonsterDB()
MonsterDB::~MonsterDB()



And just now the teacher responded, saying part two of the task is just to implement the hierarchy of the polymorphism and not getting it to work with the part 1. But would be fun to get it to work a little atleast i think. He gave this solution to the problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Monster
{
   ... 
   virtual Monster* Clone() =0;
};

class Human : public Monster
{
   Human* Clone() { return new Human(*this); }
   ...
};

void MonsterDB::Add(const Monster& monster)
{
   Monster* copy = monster.Clone();
   ...
}


So he's copying the objects, not actually using the already created ones.
Hmm, I see. I still reckon that could kick up a compiler error without an permissive flag being used.
Getting lots of errors. First is i cant create Monster objects since the clone() is abstract, in other words, no longer working with the first part of the task. (Due to Monster itself not having a implementation of it?)

 
error C2259: 'Monster' : cannot instantiate abstract class due to following members: 'Monster *Monster::Clone(void)' : is abstract


Second is the add() function, the clone() isnt working.
 
error C2662: 'Monster *Monster::Clone(void)' : cannot convert 'this' pointer from 'const Monster' to 'Monster &'
Yeah, adding the pure virtual function makes Monster an abstract class, so no instances of this can be created.

Second error is what I expected to see with that code. Making the Clone method const should fix it.

Edit: Knocked up a quick working version of this concept.
Edit 2: Little online compiler seems to be broken for this site. Here's an Ideone version: http://ideone.com/NqBs3T
Last edited on
And that makes me believe that i should just scrap this since it's not part of the task, since it makes the first part obsolete and not working. Sent him a mail to ask if he was just helping us off-task.

Yeah, that's what i figured as well, tried making it const but it still gives same error. And making it const makes the subclasses tell me it doesnt return the same and making that const creates argh argh blurg. C++ is all about these small things, cant wait to be able to understand everything, but aint got much time for this, got a parallel course in advanced c# as well, plus my full time studies.
Topic archived. No new replies allowed.