Jump to content
  • Advertisement
Sign in to follow this  
SteveDeFacto

How to use class functions as a variable?

This topic is 2806 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

With luabind you had to create functions to get and set variables in a class that you wanted to bind. This actually was very useful because it allowed me to create a really handy window class for lua but now I would like to use the class in C++ without needing to use get and set functions every time I want to change something.

Is there a way to use get and set functions as variables? Like this:


class foo
{
public:
void set_val( float in )
{
val = in;
}

float get_val()
{
return val;
}

private:
float val;

};



I want those two functions to act as though I were directly interacting with the variable.

Share this post


Link to post
Share on other sites
Advertisement
That's not possible in standard C++. However, your compiler may have extensions to do that. Ex: MSVC's __declspec(property).

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
That's not possible in standard C++. However, your compiler may have extensions to do that. Ex: MSVC's __declspec(property).


Really? Well I don't really think it would be a good idea to use functions that only work with one compiler since I am hoping to release it as an open source library.

Is there absolutely no other way to trigger a function and or block of code when a variable is set or read from? This actually seems hard to believe...

Share this post


Link to post
Share on other sites
The one way I can think of, which is very ugly, is to create a property class:


// untested
template<typename T>
class property
{
public:
property(const boost::function<T &()> &get,
const boost::function<void (const T &)> &set,
const T &init = T()) :
get_(get),
set_(set)
{
set_(init);
}

T &operator= (const T &val)
{
set_(val);
return get_();
}

const operator T &() const { return get_(); }

private:
boost::function<T &()> get_;
boost::function<void (const T &)> set_;
};


But that's ugly and heavy weight and I wouldn't recommend it. I'm showing you to put you off the idea :)

But also, perhaps step back a moment and ask yourself how many times such an interface is really desirable. The thing I don't like about properties is that the syntax suggests a simple, quick operation, when in fact anything could be happening.

I find they can be handy e.g. in Python (where there's first class support for them) on the rare occasion where you start out with a 'public' variable and it later transpires that this variable needs to be part of some invariant that didn't exist before. In this case, you can replace the variable with a property and not break the client interface.

However, would it really hurt you, in this case to simply use a public variable? Ask yourself how many people will be using the code and how widely. And ask yourself about how likely it is that the variable might be involved in some as-yet-unspecified invariant down the road. I'd posit that people put far too much stead in public/private/protected encapsulation and they can sometimes end up creating more of a development burden than would a simple public variable. Not all the time, but sometimes. I get the feeling this could be one of those times.

Share this post


Link to post
Share on other sites
Quote:
Original post by SteveDeFacto
Not for what I was doing. I was not just setting a float or int.


Luabind can call almost arbitrary code for the get/set functionality. It's in the link Kambiz posted.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
The one way I can think of, which is very ugly, is to create a property class:


// untested
template<typename T>
class property
{
public:
property(const boost::function<T &()> &get,
const boost::function<void (const T &)> &set,
const T &init = T()) :
get_(get),
set_(set)
{
set_(init);
}

T &operator= (const T &val)
{
set_(val);
return get_();
}

const operator T &() const { return get_(); }

private:
boost::function<T &()> get_;
boost::function<void (const T &)> set_;
};


But that's ugly and heavy weight and I wouldn't recommend it. I'm showing you to put you off the idea :)

But also, perhaps step back a moment and ask yourself how many times such an interface is really desirable. The thing I don't like about properties is that the syntax suggests a simple, quick operation, when in fact anything could be happening.

I find they can be handy e.g. in Python (where there's first class support for them) on the rare occasion where you start out with a 'public' variable and it later transpires that this variable needs to be part of some invariant that didn't exist before. In this case, you can replace the variable with a property and not break the client interface.

However, would it really hurt you, in this case to simply use a public variable? Ask yourself how many people will be using the code and how widely. And ask yourself about how likely it is that the variable might be involved in some as-yet-unspecified invariant down the road. I'd posit that people put far too much stead in public/private/protected encapsulation and they can sometimes end up creating more of a development burden than would a simple public variable. Not all the time, but sometimes. I get the feeling this could be one of those times.


It's a window class that has to interact with the windows API which is not as simple as just setting a variable. Here are some of the functions I turned into variables:


void E_WINDOW::set_title( std::string title )
{
SetWindowText( hWnd, title.c_str() );
}

std::string E_WINDOW::get_title()
{
char* title = NULL;
GetWindowText( hWnd, title, 256 );
return title;
}

void E_WINDOW::set_icon( std::string file )
{
HANDLE icon = LoadImage(NULL, file.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
SendMessage(hWnd, (UINT)WM_SETICON, ICON_BIG, (LPARAM)icon);
IconFileName = file;
}

std::string E_WINDOW::get_icon()
{
return IconFileName;
}

void E_WINDOW::set_left( int left )
{
RECT rect;
GetWindowRect( hWnd, &rect );
SetWindowPos( hWnd, NULL, left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top), NULL);
}

int E_WINDOW::get_left()
{
RECT rect;
GetWindowRect( hWnd, &rect );
return rect.left;
}

void E_WINDOW::set_top( int top )
{
RECT rect;
GetWindowRect( hWnd, &rect );
SetWindowPos( hWnd, NULL, rect.left, top, (rect.right - rect.left), (rect.bottom - rect.top), NULL);
}

int E_WINDOW::get_top()
{
RECT rect;
GetWindowRect( hWnd, &rect );
return rect.top;
}

void E_WINDOW::set_width( int width )
{
RECT rect;
GetWindowRect( hWnd, &rect );
SetWindowPos( hWnd, NULL, rect.left, rect.top, width, (rect.bottom - rect.top), NULL);
SwapChain->Resize();
}

int E_WINDOW::get_width()
{
RECT rect;
GetWindowRect( hWnd, &rect );
return rect.right - rect.left;
}

void E_WINDOW::set_height( int height )
{
RECT rect;
GetWindowRect( hWnd, &rect );
SetWindowPos( hWnd, NULL, rect.left, rect.top, (rect.right - rect.left), height, NULL);
SwapChain->Resize();
}

int E_WINDOW::get_height()
{
RECT rect;
GetWindowRect( hWnd, &rect );
return rect.bottom - rect.top;
}

void E_WINDOW::set_visible( bool visible )
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_VISIBLE);
if (visible)
{
if (!isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style | WS_VISIBLE );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
else
{
if (isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style & ~WS_VISIBLE );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
}

bool E_WINDOW::get_visible()
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_VISIBLE);
return isset;
}

void E_WINDOW::set_maximize( bool maximize )
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_MAXIMIZEBOX);
if (maximize)
{
if (!isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style | WS_MAXIMIZEBOX );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
else
{
if (isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style & ~WS_MAXIMIZEBOX );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
}

bool E_WINDOW::get_maximize()
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_MAXIMIZEBOX);
return isset;
}

void E_WINDOW::set_minimize( bool minimize )
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_MINIMIZEBOX);
if (minimize)
{
if (!isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style | WS_MINIMIZEBOX );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
else
{
if (isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style & ~WS_MINIMIZEBOX );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
}

bool E_WINDOW::get_minimize()
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_MINIMIZEBOX);
return isset;
}

void E_WINDOW::set_buttons( bool buttons )
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_SYSMENU);
if (buttons)
{
if (!isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style | WS_SYSMENU );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
else
{
if (isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style & ~WS_SYSMENU );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
}

bool E_WINDOW::get_buttons()
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_SYSMENU);
return isset;
}

void E_WINDOW::set_caption( bool caption )
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_CAPTION);
if (caption)
{
if (!isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style | WS_CAPTION );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
else
{
if (isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style & ~WS_CAPTION );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
}

bool E_WINDOW::get_caption()
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_CAPTION);
return isset;
}

void E_WINDOW::set_opacity( float val )
{
opacity = val;
SetLayeredWindowAttributes( hWnd, 0, (BYTE)(255 * opacity), LWA_ALPHA );
}

float E_WINDOW::get_opacity()
{
return opacity;
}

void E_WINDOW::set_size( bool size )
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_SIZEBOX);
if (size)
{
if (!isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style | WS_SIZEBOX );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
else
{
if (isset)
{
SetWindowLongPtr( hWnd, GWL_STYLE, style & ~WS_SIZEBOX );
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME );
}
}
}

bool E_WINDOW::get_size()
{
long style = GetWindowLongPtr(hWnd, GWL_STYLE);
bool isset = !!(style & WS_SIZEBOX);
return isset;
}

void E_WINDOW::set_show_cursor(bool state)
{
show_cursor = state;
POINT MousePos;
GetCursorPos(&MousePos);
if ( hWnd == WindowFromPoint(MousePos) )
{
if ( state )
{
SetCursor(LoadCursor( NULL, IDC_ARROW ));
}
else
{
SetCursor(NULL);
}
}
}

bool E_WINDOW::get_show_cursor()
{
return show_cursor;
}

void E_WINDOW::set_bgcolor(luabind::object color)
{
bgcolor = D3DXCOLOR( luabind::object_cast<float>(color[1]), luabind::object_cast<float>(color[2]), luabind::object_cast<float>(color[3]), luabind::object_cast<float>(color[4]) );
}

luabind::object E_WINDOW::get_bgcolor()
{
luabind::object table = luabind::newtable( g_Lua );
table[1] = bgcolor.r;
table[2] = bgcolor.g;
table[3] = bgcolor.b;
table[4] = bgcolor.a;
return table;
}





As you could imagine it made working with a window super easy! I also had it initialize the windows with default values which meant I only needed to set values that I wanted different then the default.

Share this post


Link to post
Share on other sites
Quote:
Original post by SteveDeFacto
Quote:
Original post by Kambiz
You can use Luabind properties to bind the variable without writing get set functions.


Not for what I was doing. I was not just setting a float or int.


So you are doing something non trivial but like it to look like a simple assignment in C++? That will just cause confusion, especially if you want to make the code available as a library.

If you want the syntactic sugar implement it in Lua (Luabind can do this) but don't hack it into C++. The easy of use an advantage of Lua, but in C++ one expects the low level interface.

Share this post


Link to post
Share on other sites
Quote:
Original post by SteveDeFacto
It's a window class that has to interact with the windows API which is not as simple as just setting a variable. Here are some of the functions I turned into variables:

*** Source Snippet Removed ***

As you could imagine it made working with a window super easy! I also had it initialize the windows with default values which meant I only needed to set values that I wanted different then the default.


I'd say stick with what you have, especially as some of the functions are non-trivial. The verbosity of C++ is something you'll have to live with.

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!