Overiding 'helper' functions

  • (2 Pages)
  • +
  • 1
  • 2

27 Replies - 517 Views - Last Post: 22 April 2013 - 03:11 PM Rate Topic: -----

#1 Nano511  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 145
  • Joined: 07-October 12

Overiding 'helper' functions

Posted 19 April 2013 - 01:09 PM

I wasnt sure how to word the title without using the prohibited words. Anyways, I think an illustration of my problem will be better than trying to explain it with words.

class Base
{
    void FireAtEnemy(){
        MakeBullet();//make bullet is called
    }
    Bullet* MakeBullet(){
        //create and return a round bullet
    }
};

class Derived
{
    Bullet* MakeBullet(){
        //create and return a rectangular bullet
    } 
};



Now when i do this..

std::vector<Base> classes;
Derived newDerived();
classes.pushBack(newDerived);

classes[0].FireAtEnemy();



classes[0].FireAtEnemy() will use the Base MakeBullet() and create a round bullet, even though classes[0] is a Derived. Derive Inherits the FireAtEnemy() method, but the inherited FireAtEnemy() method doesnt use the overidden MakeBullet() method and instead uses the Base MakeBullet() method. Sorry if my explanation of the problem is confusing. Just to be clear there are no errors or anything, I'm just trying to figure how to get a desired result.

Is This A Good Question/Topic? 0
  • +

Replies To: Overiding 'helper' functions

#2 BetaWar  Icon User is offline

  • #include "soul.h"
  • member icon

Reputation: 1148
  • View blog
  • Posts: 7,149
  • Joined: 07-September 06

Re: Overiding 'helper' functions

Posted 19 April 2013 - 01:37 PM

There is a nice keyword you are missing called virtual which tells the compiler that the function may be overwritten. For instance:

class Base
{
public:
    void FireAtEnemy(){
        MakeBullet();//make bullet is called
    }
    virtual Bullet* MakeBullet(){
        //create and return a round bullet
    }
};

class Derived: public Base
{
public:
    virtual Bullet* MakeBullet(){
        //create and return a rectangular bullet
    } 
};



should work better. I also went ahead and fixed the other syntax things I noticed.

Hope that helps.
Was This Post Helpful? 0
  • +
  • -

#3 Nano511  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 145
  • Joined: 07-October 12

Re: Overiding 'helper' functions

Posted 19 April 2013 - 01:54 PM

Sorry about the other syntax problems, they weren't in the real code though. I added the virtual keyword now but the program still never enters Derive::MakeBullet().

But i did just realize something. The program is ACTUALLY like this. See that MakeBullet has different parameters.
class Base
{
public:
    void FireAtEnemy(){
        MakeBullet();//make bullet is called
    }
    virtual Bullet* MakeBullet( int x ){
        //create and return a round bullet
    }
};

class Derived: public Base
{
public:
    virtual Bullet* MakeBullet( float y, string t){
        //create and return a rectangular bullet
    } 
};



Was This Post Helpful? 0
  • +
  • -

#4 BetaWar  Icon User is offline

  • #include "soul.h"
  • member icon

Reputation: 1148
  • View blog
  • Posts: 7,149
  • Joined: 07-September 06

Re: Overiding 'helper' functions

Posted 19 April 2013 - 02:08 PM

Well the browser lost my post, so I am going to keep this one short. The two functions you have there are completely different in C++. So, to fix that, make them have the same parameter count and types.

One potential way to accomplish this:
class Base
{
public:
    void FireAtEnemy(){
        MakeBullet();//make bullet is called
    }
    virtual Bullet* MakeBullet( float x ){
        //create and return a round bullet
    }
};

class Derived: public Base
{
public:
    Derived(string myT){
        t = myT;
    }
    virtual Bullet* MakeBullet( float y){
        //create and return a rectangular bullet
    } 
private:
    string t;
};




Hope that helps.
Was This Post Helpful? 0
  • +
  • -

#5 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2992
  • Posts: 10,337
  • Joined: 08-August 08

Re: Overiding 'helper' functions

Posted 19 April 2013 - 02:10 PM

So then your derived class has two MakeBullet methods, right?
Was This Post Helpful? 0
  • +
  • -

#6 Nano511  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 145
  • Joined: 07-October 12

Re: Overiding 'helper' functions

Posted 19 April 2013 - 02:24 PM

Oh i dun goof'd. Bullet* MakeBullet( float y, string t) is never even called anywhere in my code, that's why it isnt run. And there doesn't seem to be a good solution to sneak it in anywhere so im going to have to think of a new system for creating bullets. <_</>
Was This Post Helpful? 0
  • +
  • -

#7 Nano511  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 145
  • Joined: 07-October 12

Re: Overiding 'helper' functions

Posted 19 April 2013 - 03:50 PM

Although a question i did have was should the virtual keyword be used in the base AND derived methods like BetaWar did? I always thought it was just used in the base class.

EDIT: Also, it seems i dont have to rewrite everything. I discovered that the program is only running the virtual class, and never the Derived's overidden class.

in Turret.h the method is declared
	virtual Bullet* MakeBullet(sf::Texture& t_spriteSheet, float angle, Enemy* target){return NULL;};


Then in Turret_TrackingMissile which publicly inherits Turret, i have
	Bullet* MakeBullet(sf::Texture& t_spriteSheet, float angle, Enemy* target)
	{
		Bullet* newBullet = new Bullet_TrackingMissile(t_spriteSheet,target, xPos, yPos, (rangeDiameter/2));//create new bullet
		return newBullet;
	}



But only NULL is ever returned from the method.

This post has been edited by Nano511: 19 April 2013 - 04:04 PM

Was This Post Helpful? 0
  • +
  • -

#8 #define  Icon User is offline

  • Duke of Err
  • member icon

Reputation: 1345
  • View blog
  • Posts: 4,635
  • Joined: 19-February 09

Re: Overiding 'helper' functions

Posted 19 April 2013 - 06:20 PM

View PostNano511, on 19 April 2013 - 09:09 PM, said:

Now when i do this..

std::vector<Base> classes;
Derived newDerived();
classes.pushBack(newDerived);

classes[0].FireAtEnemy();




When you create a collection of base and derived classes, you need to use a pointer to the base class for the virtual functions to work.

std::vector<Base*> classes;
Derived *derived = new Derived();
classes.pushBack(derived);

classes[0].FireAtEnemy();


Was This Post Helpful? 1
  • +
  • -

#9 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1074
  • View blog
  • Posts: 4,533
  • Joined: 09-June 09

Re: Overiding 'helper' functions

Posted 19 April 2013 - 07:55 PM

To me it sounds like you should be abstracting the bullet type.

i.e.
class Bullet {
   double len;
public:
   Bullet(double length)
      :len(length) {}
};

class RoundBullet: public Bullet {
   double rad;
public:
   RoundBullet(double radius, double length)) 
      :Bullet(length), rad(radius) {}
};

class RectBullet: public Bullet {
   double hei, wid;
public:
   RectBullet(double height, double width, double length) {
      :Bullet(length), hei(height), wid(width) {}
};


This post has been edited by jjl: 19 April 2013 - 07:55 PM

Was This Post Helpful? 0
  • +
  • -

#10 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2992
  • Posts: 10,337
  • Joined: 08-August 08

Re: Overiding 'helper' functions

Posted 20 April 2013 - 12:23 PM

Looking at this again, I noticed that you're trying to store the objects in a vector, but vectors can only hold objects of one type, so you need to hold a pointer to the objects. This is unfortunate, because you then need to deal with memory management, negating much of the advantage of using vectors!

Here's an example:
#include <iostream>
#include <vector>

using namespace std;

class shape {
public:
	int height, base, Area;
	
	shape()
	{
		height = 10;
		base = 20;
		Area = -1;
	}
	
	virtual void set_area(){};
	
};

class rectangle: public shape {
public:
	virtual void set_area() {
		Area = height * base;
	}
};

class triangle: public shape {
public:
	virtual void set_area() {
		Area = height * base/2;
	}
};

int main(int argc, const char * argv[])
{

	vector <shape*> test;
	
	rectangle *rect_angle = new rectangle();
	triangle *tri_angle = new triangle();
	
	cout <<"Two areas initialized to -1: "<<  rect_angle->Area << "\t"<< tri_angle->Area << endl;

	// Add two shapes to the vector:
	test.push_back(rect_angle);
	test.push_back(tri_angle);
	
	// Calculate the areas for each shape:
	for (long i = 0; i < test.size(); i++) {
		test[i]->set_area();
	}

	cout <<"Show the two areas calculated by type: " << test[0]->Area << "\t"<< test[1]->Area << endl;
	
	// Free up the memory:
	for (long i = 0; i < test.size(); i++) {
		delete test[i];
		test.erase(test.begin() + i);
	}
    return 0;
}



Was This Post Helpful? 1
  • +
  • -

#11 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1074
  • View blog
  • Posts: 4,533
  • Joined: 09-June 09

Re: Overiding 'helper' functions

Posted 20 April 2013 - 01:36 PM

Just a head's up, this for loop seems pretty dangerous
	for (long i = 0; i < test.size(); i++) {
		delete test[i];
		test.erase(test.begin() + i);
	}



Erasing elements from test changes test.size() and also changes the arrangement of elements - resulting to elements not being freed correctly. I wouldn't worry about erasing, the vector's deconstructor will handle that.
Was This Post Helpful? 0
  • +
  • -

#12 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2992
  • Posts: 10,337
  • Joined: 08-August 08

Re: Overiding 'helper' functions

Posted 20 April 2013 - 01:48 PM

Maybe I've got this wrong, but I think test[i] should be a pointer to the object so delete test[i] should delete that object. I think you're thinking of delete [] test which would delete a dynamically allocated array.

What I was trying to show was that if you want to erase an element from the vector then you need to delete the object it points to.
Was This Post Helpful? 0
  • +
  • -

#13 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1074
  • View blog
  • Posts: 4,533
  • Joined: 09-June 09

Re: Overiding 'helper' functions

Posted 20 April 2013 - 02:04 PM

erase changes the size of the vector and will shift the elements accordingly. If you delete an element at index i, and then erase it at that index, elements from i + 1 to test.size() - 1 shift down. Now test[i] has a completely valid pointer which the iterator will skip on the next iteration. Make sense?

You could use erase, but it's a terribly inefficient way of deleting the elements.

while(test.size()) {
   delete test[0];
   test.erase(test.begin());
}


This post has been edited by jjl: 20 April 2013 - 02:08 PM

Was This Post Helpful? 0
  • +
  • -

#14 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2992
  • Posts: 10,337
  • Joined: 08-August 08

Re: Overiding 'helper' functions

Posted 20 April 2013 - 02:13 PM

View Postjjl, on 20 April 2013 - 05:04 PM, said:

erase changes the size of the vector and will shift the elements accordingly. If you delete an element at index i, and then erase it at that index, elements from i + 1 to test.size() - 1 shift down. Now test[i] has a completely valid pointer which the iterator will skip on the next iteration. Make sense?

Not really. Look at this version:
#include <iostream>
#include <vector>

using namespace std;

class shape {
public:
	int height, base, Area;
	
	shape()
	{
		height = 10;
		base = 20;
		Area = -1;
	}
	
	virtual void set_area(){};
	
};

class rectangle: public shape {
public:
	virtual void set_area() {
		Area = height * base;
	}
};

class triangle: public shape {
public:
	virtual void set_area() {
		Area = height * base/2;
	}
};

int main(int argc, const char * argv[])
{
	const long max = 6;
	vector <shape*> test;
	shape *ptr = NULL;
	
	for (long i = 0; i < max; i++) {
		if (i % 2 == 0) {
			ptr = new rectangle();
		} else {
			ptr = new triangle();
		}
		test.push_back(ptr);
		test[test.size()-1]->base += i;
	}
	
	// Calculate the areas for each shape:
	for (long i = 0; i < test.size(); i++) {
		test[i]->set_area();
		cout <<"Area calculated by type: " << test[i]->Area << endl;
	}

	delete test[1];
	test.erase(test.begin()+1);
	cout << endl << endl;
	for (long i = 0; i < test.size(); i++) {
		cout <<"Showing Area calculated by type: " << test[i]->Area << endl;
	}

    return 0;
}


and it's output:
Area calculated by type: 200
Area calculated by type: 105
Area calculated by type: 220
Area calculated by type: 115
Area calculated by type: 240
Area calculated by type: 125


Showing Area calculated by type: 200
Showing Area calculated by type: 220
Showing Area calculated by type: 115
Showing Area calculated by type: 240
Showing Area calculated by type: 125


In deleting element 1 and erasing its pointer from the vector we remove the second item from the list (area = 105).

There are two things that need to be removed: the object and the pointer to the object, and in that order. Simply erasing the pointer from the vector would not free the memory used by the object, so you'd have a memory leak.
Was This Post Helpful? 0
  • +
  • -

#15 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1074
  • View blog
  • Posts: 4,533
  • Joined: 09-June 09

Re: Overiding 'helper' functions

Posted 20 April 2013 - 02:27 PM

Your completly missing the point of what I am saying, so I'll show a demo.

#include <iostream>
#include <vector>

int main() {
   std::vector<int*> ints;

   /* create dynamic ints*/
   for(int i=0; i<10; i++) {
      ints.push_back(new int);
   }

   /* your method of deleting them */
   for(int i=0; i<ints.size(); i++) {
      delete ints[i];
      ints[i] = NULL;
      ints.erase(ints.begin() + i);

      /* print the iterator */
      std::cout<<"i = "<<i<<std::endl;
   }

   return 0;
}



Running the code compiled under g++ produces the following output.

Quote

i = 0
i = 1
i = 2
i = 3
i = 4


There were only 5 deletions, not 10. Hopefully this helps confirm my point.

This post has been edited by jjl: 20 April 2013 - 02:28 PM

Was This Post Helpful? 1
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2