Jump to content
  • Advertisement
Sign in to follow this  
KKTHXBYE

Assign different functions to different structs in std::vector<>

This topic is 1007 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am wondering if theres another way of executing a function like that:

keep in mind that this is pseudocode

 

struct MyStruct
{

void onClick(); //function that will be executed

};

 

std::vector<MyStruct> ahue;

 

 

void Button4_OnClick()

{

}

 

void main()

{

ahue[4].onClick() = Button4_OnClick(); 

}

 

do i have to always assign a pointer to function or theres another way, i am asking because in borland c++ builder [im not sure how they do that]

you place a button and theres already a code that executes onClick property. so you dont need to worry about setting pointers to a function etc..

 

 

Share this post


Link to post
Share on other sites
Advertisement

welp, thats not exactly what i expected.

But actually a constructor that assigns a function is quite an awesome trick to do :) +1

 

im waiting for more other examples to see what kind of thing would fit the most so far your wins.

 

I'm now implementing popup menus in opengl and i need to call a function (on item click) defined somewhere else in code.

Share this post


Link to post
Share on other sites
Basically, you're doing a call back function. BitMaster gave you the C++ method. Here is how it was done in C:
 
#include <iostream>

struct my_struct {
	void (*my_func)(); // The syntax here is important! You are not declaring a function. You're declaring a pointer to a function.
};

void test_func()
{
	std::cout << "test function" << std::endl;
}

int main()
{
	my_struct	test;

	test.my_func = &test_func; // Assign the address of test_func to test.my_func.

	test.my_func();

	while (1);
}
Tested and it works. I would say that BitMaster's is better as it does it in a C++ fashion, but I don't think it really matters.

You do have to assign the pointer to the function for this to work. "void" is a valid return type. This will not work:
 
test.my_func = test_func(); // The return value of test_func is being assigned to test.my_func instead of the address of test_func.
Edited by MarkS

Share this post


Link to post
Share on other sites

as stated above, procedural variables are the standard way to do it:

 

from caveman v3.0....

 

typedef:

typedef void functiontype1();
 
forward declaration:
void drinkliquid();
 
variable declaration:
struct actionrec
{
...
functiontype1 *proceedure;
...
};
 
 
assignment:
action[DRINK].proceedure=drinkliquid;
 
invocation:
void doactionmodeB(int cm1)
{
int a;
a=7+cm[cm1].mood/13;
if (frame<=a) action[cm[cm1].current_action].proceedure();
}
 

where cm[cm1].currect_action==DRINK

 

so doactionmodeB calls action[DRINK].porceedure(), which is void drinkliquid();

Share this post


Link to post
Share on other sites
Another way to do this is to use polymorphism. This isn't necessarily superior to the above, but I thought I'd mention it for completeness. It is used in some libraries.

The code equivalent to the example is: 
struct MyStruct
{
  virtual void onClick() = 0; //function that will be executed
};
 
std::vector<unique_ptr<MyStruct>> ahue;
 
 
void Button4_OnClick()
{
}
 
struct Button4: public MyStruct{
  void onClick()
  {
     Button4_OnClick()
  }
};

void main()
{  
  ahue.emplace_back(new Button4()); 
}

Share this post


Link to post
Share on other sites

Another way to do this is to use polymorphism. This isn't necessarily superior to the above, but I thought I'd mention it for completeness. It is used in some libraries.

The code equivalent to the example is: 

struct MyStruct
{
  virtual void onClick() = 0; //function that will be executed
};


Two nitpicks with that: first, anything with a virtual function really should get a virtual destructor as well. I once ran into really annoying leaks because someone else did not stick to that rule. Thankfully, many modern compilers will warn you about it.

Second, that's an implementation of the observer pattern. While it can be useful if you need more than one function to be called in response to different types of events but for just a single function I find it more like an anti-pattern imported from languages such as Java where you have no other choice.

Share this post


Link to post
Share on other sites

Another way to do this is to use polymorphism. This isn't necessarily superior to the above, but I thought I'd mention it for completeness. It is used in some libraries.

The code equivalent to the example is: 

struct MyStruct
{
  virtual void onClick() = 0; //function that will be executed
};


Two nitpicks with that: first, anything with a virtual function really should get a virtual destructor as well. I once ran into really annoying leaks because someone else did not stick to that rule. Thankfully, many modern compilers will warn you about it.

Second, that's an implementation of the observer pattern. While it can be useful if you need more than one function to be called in response to different types of events but for just a single function I find it more like an anti-pattern imported from languages such as Java where you have no other choice.

Both valid points. However, if you need one callback, you may soon need multiple. In this case you might want to support on_hover, on_select, and on_pressed (if it's possible to use the keyboard to select and press the button), so the observer pattern may be viable.

Share this post


Link to post
Share on other sites
True, however in a lot of cases it's not immediately obvious that you will ever need more than one callback type. In these cases I would strongly recommend against the polymorphism-way in C++.

In Java for example creating a quick anonymous inner class is extremely simple. It even has access to data from its enclosing scope without any extra work.
In C++ you need to define your (possibly local) observer implementation. If you need access to any data from an enclosing scope you have to transfer it there somehow which is some extra boilerplate. You might even be in a bit of a pickle regarding lifetime management of the observer.
Especially with C++11 these kind of problems don't really exist with lambdas. But even before C++11 you could reduce the complexity a lot with, for example, Boost's function objects, bind and lambdas.

Share this post


Link to post
Share on other sites
Description Resource Path Location Type
ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say '&TTERRA_TEX_OSD::SetNoBlend' [-fpermissive]
 
 
 
code:
 
void (*MenuOnClick)();


void SetNoBlend() { brush_blend = 0; }


BrushMenu.Items[3].Items[0].MenuOnClick = &SetNoBlend;

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!