Author Topic: Quick Programming Question  (Read 1698 times)

Offline Spikerocks101

  • Hero Member
  • *****
  • Posts: 711
Quick Programming Question
« on: January 19, 2010, 03:12:44 AM »
This code I put won't work, but it's the idea of what I want to do:

class building
{
public:
void load();
}garage, agridome;

void garage::load()
{
if (vechile(x,y))
vechile.repair();
}

void agridome::load()
{
if (vechile(x,y))
vechile.load(1000,food);
}

int main()
{
building urbuildings[5];
urbuildings[0] = garage;
urbuildings[1] = agridome;
return 0;
}

well, if u got that, i want it so i can have an array of buildings, but each one has different functions. if you need me to clear it more up, ask how.
I AM YOUR PET ROCK!!!!!!

Offline Spikerocks101

  • Hero Member
  • *****
  • Posts: 711
Quick Programming Question
« Reply #1 on: January 19, 2010, 02:16:14 PM »
I want to have a array of a class (say, the class is Vehicle, so the array would be "Vehicle yourVehicle[10]"), but I also want it so I can have different function for each vehicle (say build for ConVec is different then build for Robo_Miner), yet I want to set what each one is in the array (yourVehicle[1] = ConVec, yourVehicle[2] = Robo_Miner), how can I do this? Here's an idea of how it would be done, but won't work of course:

class Vehicle
{
public:
virutal void build();
}ConVec,Robo_Miner;

void ConVec::build()
{
//...code
}

void Robo_Miner::build()
{
//...code
}

int main()
{
Vechile yourVehicle[5];
yourVehicle[1] = ConVec;
yourVehicle[2] = Robo_Miner;
return o;
}

So yes, is it possible?
 
I AM YOUR PET ROCK!!!!!!

Offline Freeza-CII

  • Administrator
  • Hero Member
  • *****
  • Posts: 2308
Quick Programming Question
« Reply #2 on: January 19, 2010, 04:25:50 PM »
you should really put these in the programming section i moved your other one there just today.

Offline Spikerocks101

  • Hero Member
  • *****
  • Posts: 711
Quick Programming Question
« Reply #3 on: January 19, 2010, 04:49:43 PM »
oh, u moved it... i didnt know. i thought i must have forgotten to post it, or it got deleted. sorry. i put in other, since anything can go in other.
« Last Edit: January 19, 2010, 04:50:54 PM by Spikerocks101 »
I AM YOUR PET ROCK!!!!!!

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Quick Programming Question
« Reply #4 on: January 20, 2010, 01:15:03 AM »
Moved and merged topics. They are essentially the same question.


What you seem to be asking about, is how to use virtual functions, and run-time/dynamic dispatch. Here is how you make it work.


First, you create a base class with the commonalities in it, such as functions with the same name and parameter list and return type.
Code: [Select]
class ConstructionVehicle // : Vehicle  // (Probably derived from a Vehicle class)
{
public:
  virtual void build() = 0;  // Pure virtual function (=0), has no implementation
};

The "= 0" part is important, otherwise the compiler will complain if you don't supply a function definition, which it won't really make sense to have in a base class. After all, how would the function know to build anything if it didn't yet know what it was building. Also keep in mind that a class with any pure virtual functions can never be instantiated. It can only be derived from. The derived classes must implement those missing functions before a class of that type can be created.

Next you create your derived classes that inherit from the base class.
Code: [Select]
class ConVec : public ConstructionVehicle  // Dervied from above base class
{
public:
  void build();  // Virtual is optional, definately don't use =0 (pure virtual)
};

class RoboMiner : public ConstructionVehicle // Derived from above base class
{
public:
  void build();  // Virtual is optional, definately don't use =0 (pure virtual)
};

Now make sure to implement those functions in the derived class, each with their own respective code.
Code: [Select]
void ConVec::build()
{
  // ConVec construction code goes here....
}

void RoboMiner::build()
{
  // RoboMiner construction code goes here....
}

Now you create instances of the derived class, and store them using a pointer to the base class.
Code: [Select]
int main()
{
  // Means "ConstructionVehicle*[2] builderArray;" in Java/D notation (which is usually easier to read)
  ConstructionVehicle *builderArray[2];

  // Populate the array with construction vehicle instances (using derived classes)
  // This uses dynamic memory allocation (flexible, but a little slower)
  builderArray[0] = new ConVec();
  builderArray[1] = new RoboMiner();
  // Similarly, you could have used static memory allocation (less flexible, but fast)
  //ConVec conVec();
  //RoboMiner roboMiner();
  //builderArray[0] = &conVec;
  //builderArray[1] = &roboMiner;

  int i;

  // Call derived build function of each class
  for (i = 0; i < 2; ++i)
  {
    builderArray[i]->build();  // Use -> instead of . notation, since we're using pointers
  }
}

Then the proper build function will be called for each derived class. This is easily verified with two different cout/printf statements for those function bodies.

Note that it is very important that instances created of the derived classes are stored into pointers of the base class type for the dynamic dispatch to work and be useful.


I should point out that this will not work without the virtual declaration in the base class. You could remove the pure virtual part and it'd still work, provided you stubbed out a default build function to be inherited by the other classes. The virtual keywork is what tells the compiler to use a virtual function table to figure out what function to call at runtime, rather than hardcode a function address at the point of call. Without the virtual keywork, you would be calling the build function on the base class instead of the derived classes. Keep in mind that virtual functions take slightly longer to call due to the table lookup. This is almost never an issue, but if you have a tiny function with little to no code in it, and it's called many times in a tight loop, you may notice a performance hit.

Also note that I dropped the virtual keywork in the derived classes. This is because I don't expect any classes to derive from those last two classes. They are essentially "leaf" classes in the class hierarchy tree. (In Java, virtual seems to be the default, and "final" methods I believe are the non-virtual ones, so they've reversed where you need to use a keyword). The point of not declaring the leaf class functions as virtual, is to allow for some speed optimization. If the compiler knows for sure what the data type is, it can make a direct call using a hardcoded function address. This happens if you call functions through a variable of the derived class type rather than the base class type, or if you call other member functions from within the class. If you declare the function as virtual in the derived class, than the compiler assumes there may be more derived classes, and so the virtual function table must be used in those cases as well.
Code: [Select]
void f()
{
  // Create pointers to base and derived classes
  ConstructionVehicle* cv1;
  ConVec* cv2;
  
  // Fill in those pointers with objects of the same type
  cv1 = new ConVec();
  cv2 = new ConVec();

  // Call a function declared as virtual in the base class
  cv1->build();  // Virtual function class, slightly slower (cv1 is of type ConstructionVehicle*, which declares build as virtual)
  cv2->build();  // Direct call, faster (cv2 is of type ConVec*, which does not declare build as virtual)
}


Note you may want to look into interfaced based programming. Interfaced based programming suggests only pure virtual functions be shared, and not regular functions or class member variables. An often good source of information for interfaced based programming are documents describing COM (the Component Object Model), although, be aware that interfaces are just one of the fundamentals of COM, and that COM added a lot of other things, which a number of people think aren't so hot. These days COM is considered somewhat of a legacy technology, but interfaced based programming is probably more important than ever.
« Last Edit: January 20, 2010, 01:21:13 AM by Hooman »

Offline Spikerocks101

  • Hero Member
  • *****
  • Posts: 711
Quick Programming Question
« Reply #5 on: January 20, 2010, 01:46:32 AM »
You can delete my first post, becauseI didnt know freeza moved it before, but any ways, YOU ARE A GO... od person hooman, because u made my coding so much easier. thanks mate. you get a programmable cookie, WHICH CAN BE ANY FLAVOR!

Edit: Another question. How does OP2 do X, Y coordinates? I know for vehicles is simpe X, Y, but how does it do it for buildings? I am assuming X, Y, length, and width. Would like to know. BTW, I am working on the OP2.5 for Linux thing I promised before, after being encouraged by TH300 and Savant_Ace.
« Last Edit: January 20, 2010, 02:13:15 AM by Spikerocks101 »
I AM YOUR PET ROCK!!!!!!

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Quick Programming Question
« Reply #6 on: January 20, 2010, 10:57:48 PM »
Outpost 2 just stores the center point of each unit (pixel based, so units can transition smoothly between tiles). This is where combat units target. The type of the unit has a size associated with it, and that can be used to find the space occupied. Note that the game engine assumes integer tile sizes, but the graphics drawing engine is pixel based. The graphics may also have a pixel offset, so the "center" is where combat units fire at, but the graphics may extend in a non-symmetric way. That offset would only apply to drawing of graphics though, not the game engine, which keeps things mostly tile aligned.

Each unit has an (x, y) coordinate (pixel based), so memory is used for each unit. Each unit type would have dimension information, and that is stored only once per unit type, and all units of that type share the same data.


I'm not entirely convinced this is the best way to do it, but it seems to work.