Advertisement

Virtual Inheritance Method Problem

Started by August 22, 2000 12:08 AM
6 comments, last by 40 Thieves 24 years, 4 months ago
I have this problem here see... and I don''t know the answer.... which is why I suppose it''s a problem. I''m working on a checkers program, and to control the dudes on the board I''ve created myself a little heiarchy. It starts with a Piece class and from that is derived a Pawn class and a King class to handle the two types of pieces in the game. I''ve created by game board with the following code: Piece* Board[8][8]; I then set all the pointers to null like so: for(x=0;x<8;x++) { for(y=0;y<8;y++) { Board[x][y] = NULL; }; }; then i set up my board in a loop which has this line at the heart: Board[x][y] = new Pawn(x,y,TEAM); and all this is fine and dandy. Next i try to access one of the functions of the Pawn class. Now in the Piece class the function is defined with this: public: virtual void fillPossibleMoves(); and in the Pawn class it is defined like this: public: void fillPossibleMoves(Piece* board[8][8], Point dir); but I try to call the function like this: if(Board[2][2]!=NULL) { Board[2][2]->fillPossibleMoves(Board, BLACKdir); Board[2][2]->listMovesReady(); }; but i get the error that function Piece::fillPossibleMoves() does not take 2 parameters. My understanding of virtual functions was that by using pointers this way it knows which functions to call. Here are the full header files if they help any.
    
class Piece {
	protected:
		Point pos;
		TEAM myTeam;
		LinkedList<Point> possible;
		virtual void checkJump();

	public:
		Piece() {};
		Piece(Point p, TEAM t) { myTeam=t; pos=p; };
		Piece(int x, int y, TEAM t) { myTeam=t; pos.x=x; pos.y=y; };
		virtual ~Piece() {;};
		virtual Piece* Clone() { return(new Piece(*this)); };
		void setTeam(TEAM t) { myTeam = t; };
		TEAM getTeam() { return(myTeam); };
		void setCoord(Point p) { pos=p; };
		void setCoord(int x, int y) { pos.x=x; pos.y=y; };
		void getCoord(Point &p) { p=pos; };
		void getCoord(int &x, int &y) { x=pos.x; y=pos.y; };
		int movesReady() { return(possible.getLength()); };
		void clearPossibleMoves();
		void listMovesReady();
		virtual void fillPossibleMoves();
};

class Pawn : public Piece {
	public:
		Pawn() : Piece() {};
		Pawn(Point p, TEAM t) : Piece(p, t) {};
		Pawn(int x, int y, TEAM t) : Piece(x, y, t) {};
		virtual ~Pawn() {;};
		virtual Piece* Clone() { return(new Pawn(*this)); };
		void fillPossibleMoves(Piece* board[8][8], Point dir);
	
	protected:
		void checkJump(Piece* board[8][8], Point p, Point dir);
};

class King : public Piece {
	public:
		King() : Piece() {};
		King(Point p, TEAM t) : Piece(p, t) {};
		King(int x, int y, TEAM t) : Piece(x, y, t) {};
		virtual ~King() {;};
		virtual Piece* Clone() { return(new King(*this)); };
		void fillPossibleMoves(Piece* board[8][8]);
	
	protected:
		void checkJump(Piece* board[8][8], Point p);
};
    
40 www.databyss.com www.omlettesoft.com "Don''t meddle in the affairs of wizards, for they are subtle and quick to anger."
-40
In order for the virtual function fillPossibleMoves to work correctly, you need to make sure that the derived classes have the same function signature as the base class.

You base class takes no parameters while your derived classes take varying parameters based.

YAP-YFIO,
deadlinegrunt

~deadlinegrunt

Advertisement
Virtual functions must have the same signiture throught the class hierarchy. What that means is that when you define the base class virtual function with out any parameters, and then redfine it in the derived with parameters, you are creating two seperate functions. This is called function overloading.

Define the function in your base class so that it takes the same parameters as the derived classes and you are in buisness.
I don''t know why this would let me edit my post so forget it and read this one instead. Anyways it should read like this:

In order for the virtual function fillPossibleMoves to work correctly, you need to make sure that the derived classes have the same function signature as the base class.

You base class takes no parameters while your derived classes take varying parameters.

YAP-YFIO,
deadlinegrunt

~deadlinegrunt

The definitions you have look like they should work...although I'm not really Mr. OOP

The only thing I can think of is that board[2][2] isn't a pawn. Your test condition fails only if it's NULL, not if it's NULL or a piece type other than a pawn. As it stands, there isn't any way that the outside world can tell what type of piece any given Piece* variable is.

There, you see? Two people responded before me who knew what they were talking about. Which is why I'm not Mr. OOP

Edited by - TheHoff on August 22, 2000 1:33:13 AM
Thanks guys for the quick response time... a couple questions.

Well then shouldn''t my code work based on function overloading then? If not how can I get this to work... should i rewrite my base class definition so it takes the same parameters? Or is there another way, that could be better?

40

www.databyss.com
www.omlettesoft.com

"Don''t meddle in the affairs of wizards, for they are subtle and quick to anger."
-40
Advertisement
You might play around with this little example I put together. I think it pretty much addresses what you are trying to do. In an effort to make sure you learn I made sure it had nothing to do with chess.

Also, don''t get caught up with the STL stuff. That''s not the lesson here...

    #include &ltiostream>#include &ltstring>#include &ltvector>using namespace std;class Base{public:	virtual void f() = 0;	virtual ~Base() {};};class Derived1 : public Base{public:	void f()	{ cout << endl << "Derived1 called." << endl; }};class Derived2 : public Base{public:	Derived2(const char* txt)	{  text = txt; }	void f()	{ cout << endl << text << endl; }protected:	string	text;};int main(int argc, char** argv, char** env){	vector&ltBase*>			p;	vector&ltBase*>::iterator		index;	p.push_back(new Derived1);	p.push_back(new Derived2("Derived2 called."));	p.push_back(new Derived1);	p.push_back(new Derived2("Same thing but with a twist."));	for(index = p.begin(); index < p.end(); index++)	{		index[0]-&gtf();	}	return 0;}    


(Geesh, don''t know why I can''t get this HTML crap down)

YAP-YFIO,
deadlinegrunt

~deadlinegrunt

Unlike TheHoff, you can call me "Mr. OOP".

First, some definitions:
"virtual inheritance" is what you have when you have a diamond-shaped inheritance pattern. In this case, derived classes are declared like so: class B : virtual public A. This is not what you have here, i.e. you're using the wrong terminology. You're just using virtual functions, which is a part of inheritence.

The way inheritance should work is that the the base class decides the interface (i.e. public functions) for all derived classes. You can add on to the public function list, which is what you do when you overload a function . A function overload is not the same function at all--it's a completely new function.

When you add a function in such a way in the derived class, the base class has no knowledge of it, so there is no way to get to that function via the base class pointer. This is why your base class call to the function is looking for a fillPossibleMoves function with no parameters--because that's how you declared the function in the base class (fillPossibleMoves (void)).

The solution is this: anything you want to be able to do through the base class pointer (Piece*) must be declared that way in the base class. If you want fillPossibleMoves to accept the entire board and a direction, then it must be declared that way in the base class:
class Piece
{
public:
void fillPossibleMoves (Piece* board[8][8], Point dir);
};

Furthermore, each derived class must declare the function exactly this way; otherwise, you'll be creating a new function in the derived class and the base class pointer will have no way to access it.

Also, if you're never going to create an object of type Piece, and will only have pointers to Piece, I'd suggest making the above function empty:
void fillPossibleMoves (Piece* board[8][8], Point dir) = 0;

This will make Piece an abstract class, and the base class version of fillPossibleMoves will never be called because it doesn't exist. Furthermore, derived classes MUST override this function or they cannot be created.

Edited by - Stoffel on August 22, 2000 1:24:23 PM

This topic is closed to new replies.

Advertisement