OO: My monster class doesn't compile! Need help!

Started by
8 comments, last by xjussix 22 years, 8 months ago
I''m practising my skills in the field of OO and made a simple MOnster class. The I derived a Grunt class from it, but my compiler doesn''t seem too happy about this stuff:
  
#include <iostream.h>
#include <string.h>

//The main monster class

class CMonster
{
	int strength;
	int weapon;
	int armor;
public:
	CMonster();
	CMonster(int, int, int);
	virtual ~CMonster();
	virtual void Attack();
	virtual void Move();
};
CMonster::CMonster(int p_str, int p_wpn, int p_armor)
{
	strength = p_str;
	weapon = p_wpn;
	armor = p_armor;
}
void CMonster::Attack()
{
	cout<<"Monster attacks!\n";
}
void CMonster::Move()
{
	cout<<"Monster moves!\n";
}

//Derived class

class CGrunt : public CMonster
{
	char name[10];
public:
	CGrunt();
	CGrunt(int, int, int, const char *);
	~CGrunt();
	void Attack();
	void Move();
};
CGrunt::CGrunt(int p_str, int p_wpn, int p_armor, const char *p_name) : CMonster(p_str, p_wpn, p_armor)
{	
	strcpy(name, p_name);
}
void CGrunt::Attack()
{
	cout<<name<<" attacks!\n";
}
void CGrunt::Move()
{
	cout<<name<<" moves!\n";
}

int main()
{
	CMonster *monster = new CMonster(1,2,3);
	CMonster *xjussix = new CGrunt(1,2,3, "xjussix");
	xjussix->Move();
	xjussix->Attack();
	monster->Attack();
	monster->Move();
	delete monster;
	delete xjussix;
	return 0;
}
  
error LNK2001: unresolved external symbol "public: virtual __thiscall CMonster::~CMonster(void)" (??1CMonster@@UAE@XZ) error LNK2001: unresolved external symbol "public: virtual __thiscall CGrunt::~CGrunt(void)" (??1CGrunt@@UAE@XZ) Debug/TYCPP21.exe : fatal error LNK1120: 2 unresolved externals My first completed game! Where''s that???
- Just another sad bastard
Advertisement
Well, what about implementing those functions? for example, the Monster destructor is declared, but not implemented; add sth like that

CMonster::~CMonster()

{

}

same for Grunt destructor
THANK YOU! Stupid ''ol me strikes again
I knew there was stupid mistake and there was. BTW, do I always have to implement destructors, or do I have to do that only when I have virtual functions in a class?

My first completed game! Where''s that???
- Just another sad bastard
Basically, if you declare it you have to implement it.

If you didn''t declare the destructor in your code, the compiler would generate one for you (of course it woulnd''t really do anything) without giving you an error.

Same applies for constructor, copy constructor, etc.

In general its almost always better to implement these than to allow the compiler to do it for you, and use virtual wisely on the destructors, especially if you know you''re going to be subclassing.
quote:Original post by gmcbay
Basically, if you declare it you have to implement it.

Untrue, unfortunately. It''s perfectly legal to declare away to your heart''s content: free functions, member functions, external variables, anything. Your code will still compile--unless you use those names.

This, IMHO, is extremely unfortunate. I''m sure LINT picks this up (we don''t use it hear, maybe we should). I don''t know how many times I''ve gone picking through a class heirarchy and found, "Wait a minute, I never implemented this function and nobody ever calls it, what''s it supposed to be doing in here again?"

So the real rule is, if you USE it, you have to implement it. If you declare it, you SHOULD implement it, but the compiler does not force you to (because it wouldn''t know until link time).
another possible refinement here...

because it''s a constructor it''s likely to always be used because a constructor is automatically called when you define an object of a given class.

maybe the compiler is forcing you to implement the constructor because it knows it will be called.

WeP
http://www.planetzztpp.com
WePhttp://www.planetzztpp.com
quote:Untrue, unfortunately. It''s perfectly legal to declare away to your heart''s content: free functions, member functions, external variables, anything. Your code will still compile--unless you use those names.

True, but constructors and destructors are never called explicitly by name. That is, you can''t code classInstance.className() to call a constructor or classInstance.~className() to call a destructor. I think that gmcbay meant that if you declare a constructor, you must implement it if any objects are created using that constructor and if you declare the destructor for a class you must also implement that if any objects of the class are created (and therefore eventually destroyed). You can get away with declaring and not implementing constructors only if no objects are created with that constructor.

-Sean

"we need common-sense judges who understand that our rights were derived from God. And those are the kind of judges I intend to put on the bench." - GW Bush"no religious Test shall ever be required as a Qualification to any Office or public Trust under the United States." - Article VI of the US Constitution.
quote:Original post by Sean99
True, but constructors and destructors are never called explicitly by name. That is, you can''t code classInstance.className() to call a constructor or classInstance.~className() to call a destructor.

Yes you can. Here''s a macro from the MSVC STL:
#define _DESTRUCTOR(ty, ptr) (ptr)->~ty()
As for constructors, they can be called by name, but not as a member function.

On an unrelated point: for people who keep forgetting to implement functions they declared in the header file, try doing the class declaration, and then copying all the function prototypes out and pasting them into your cpp file. That way, you have all the functions there, ready for you to implement them (even if this only involves an empty implementation, or a ''throw "not implemented yet!"'' or some other placeholder.)
That''ll teach me to jump in without having all the facts. Up until today I was pretty secure in my knowledge of constructors and destructors.

Allow me to jump into defensive mode for a minute :
What I was trying to do was point out that although most functions can be declared and not implemented as long as no explicit function call is made to them, constructors and destructors are a special case because (most of the time at least, as I have just learned) you don''t see the function call in the code. You could say an object declaration or dynamic allocation is the call to the constructor and I won''t argue, but in the case of the default constructor, it looks even less like a regular function call. And to be honest, I didn''t look closely at the original poster''s code and thought part of his problem was with declaring but not implementing the default constructor (which is true but I see now he didn''t create any objects with the default). But it''s certainly rare to see an explicit call to the destructor (or am I just not looking at enough code from other programmers?)

Anybody ever use "ptr->~ty();" or know how it differs from "delete ptr;"? Is it just a case of two ways of doing the same thing?

-Sean
"we need common-sense judges who understand that our rights were derived from God. And those are the kind of judges I intend to put on the bench." - GW Bush"no religious Test shall ever be required as a Qualification to any Office or public Trust under the United States." - Article VI of the US Constitution.
It''s used by STL''s construct & destruct functions for in-place construction. It''s usually used when you override new/delete, e.g. have your own memory scheme in place. For instance, say you have a fixed pool of 100 Widgets in your application. You pre-allocate the memory (e.g. with malloc), but you don''t call the ctor until they''re used. In the function that gets a Widget, you specifically call the in-place new (which only calls the ctor without allocating any memory) giving the address of the new Widget you''re creating. Likewise, you would call the in-place delete which calls the dtor but doesn''t free any memory.

This topic is closed to new replies.

Advertisement