Jump to content
  • Advertisement
Sign in to follow this  
Toolmaker

Getting rid of Get/Set functions

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

A friend of mine asked me today if I knew a little trick to help him save the hassle of writing 10 get and 10 set methods. So I came up with a little nifty macro magic that might save you from writing those functions too. If you have basic Getter/Setters that don't go any check, using these macro's might save you 30 minutes of writing boring code.
// Getter/Setter macro's
#define SETTER(ObjectType, Varname) void Set##Varname(const ObjectType& value){ m_##Varname = value; }
#define GETTER(ObjectType, Varname) const ObjectType& Get##Varname(){ return m_##Varname; }
#define GETTERSETTER(ObjectType, Varname) void Set##Varname(const ObjectType& value){ m_##Varname = value; }const ObjectType& Get##Varname(){ return m_##Varname; }

// Get/Set function calls
#define GET(Varname) Get##Varname()
#define SET(Varname, value) Set##Varname(value)





Basic usage is like this:
class Foo
{
public:
    GETTERSETTER(float, fScaling);
    GETTERSETTER(float, fRotation);
    GETTER(std::string, TypeOf);
    SETTER(float, WeaponDamage);

private:
    float       m_fScaling;
    float       m_fRotation;
    std::string m_TypeOf;
    int         m_WeaponDamage;
};

Foo MyObject;
MyObject.SET(fScaling, 1.0f);
MyObject.SET(WeaponDamage, 10);
std::string Type = MyObject.GET(TypeOf);
Just wanted to share. The macro's aren't THE best solution, but are a quick work around if you need alot of accessor functions that don't do any checking. Feel free to use this code in whatever way, except to take over the world. Toolmaker

Share this post


Link to post
Share on other sites
Advertisement
#define SETTER(ObjectType, Varname) void Set##Varname(ObjectType value){ m_##Varname = value; }
^ Bad

#define SETTER(ObjectType, Varname) void Set##Varname(const ObjectType& value){ m_##Varname = value; }
^ Better

#define GETTER(ObjectType, Varname) ObjectType Get##Varname(){ return m_##Varname; }
^ Bad

#define GETTER(ObjectType, Varname) const ObjectType& Get##Varname() const { return m_##Varname; }
^ Better

EDIT: Damn, you edited your post :P

Share this post


Link to post
Share on other sites
Sorry, but that didn't seem to really help much. If you expanded the macros to declare the variable itself as well, that would look a little better. Then you would be able to do something like this:


class SomeClass
{
DECLARE_R(float, m_fReadOnly);
DECLARE_RW(float, m_fReadWrite);
DECLARE_W(float, m_fWriteOnly);

public:
SomeClass() { ... }
...
};


EDIT: I agree with Oluseyi, but if you need it, this way would still look cleaner. I really don't mind a quick copy/paste/edit to make my getters/setters, and I often do custom things in them that couldn't be handled by generic macros like that. By that, I mean validation or extra calculations to update something else.

Share this post


Link to post
Share on other sites
Quote:
Original post by Toolmaker
A friend of mine asked me today if I knew a little trick to help him save the hassle of writing 10 get and 10 set methods. So I came up with a little nifty macro magic that might save you from writing those functions too.

If you have basic Getter/Setters that don't go any check, using these macro's might save you 30 minutes of writing boring code.


i'd be concerned for your friend, first there seems to be no state invariant to maintain because the setters "don't do any checks" so having a bunch a of getters & setters is compleletly redundant it also seems from the high number of fined grained member functions i.e. the getter & setters that its representation does not vary so its seems that he has nothing more than a plain data structure there-for the members should just be public.

if it's mean't to represent a proper user-defined type then i would say he has the wrong or mixed the levels of abstraction and he probably should group some of those members into there own separate classes.

Share this post


Link to post
Share on other sites
Quote:
Original post by Toolmaker
A friend of mine asked me today if I knew a little trick to help him save the hassle of writing 10 get and 10 set methods...
Are all 10 getters and setters necessary? Maybe they are, but in my experience using getters and setters is a "quick and dirty" solution. You may be better off just using a struct with public wrapper classes. So what exactly does the class in question do? Maybe we can find a better way.

Share this post


Link to post
Share on other sites
If you've got both get and set functions then the variables might as well be public since it can be accessed by everything else anyway. If you still want the variables to be hidden in general but accessable by certain other classes/functions then declare these as friends. Instead of having both a set and get you could always just use this one instead:


class Cow
{
private:
int numLegs;

public:
int& AccessNumLegs() { return numLegs; }
};

int nLegsA = Cow.AccessNumLegs();
nLegsA++;

int& nLegsB = Cow.AccessNumLegs();
nLegsB++;






This way Cow::AccessNumLegs can be used to get legs or set legs. nLegsA is a copy and so can be changed without altering Cow just like using Get, whereas changing nLegsB will alter Cow::numLegs since its a reference and so acts like Set. Get and Set in one :) Not monkey proof though.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Wait a sec. I thought one of the primary purposes of getters/setters is to hide the implementation of the data so that now or at some future time you can change the implementation without changing the consumers of your class.

Just because there's no point at this time doesn't mean you should discard the getter/setter. It might be necessary in the future - thus the general rule to wrap it.

I'm coming from a primarily application programming background where we actually reuse our objects and code - a lot - whereas with game programming you tend to use and define it once, but I think the rule is a good one for general use.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Wait a sec. I thought one of the primary purposes of getters/setters is to hide the implementation of the data so that now or at some future time you can change the implementation without changing the consumers of your class.

This is generally the purpose of getters and setters. However, do you really need to expose these properties to the public? That is where the design issues come in. Often it is better to change your public interface so that they don't need these getters and setters.

In building getters and setters you are inheritly binding yourself to a particular implementation. While you may be able to change the underlying behavior of the getter/setter, overall you have exposed an internal detail to the public (the datatype specifically) which they may not even need to know.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Wait a sec. I thought one of the primary purposes of getters/setters is to hide the implementation of the data so that now or at some future time you can change the implementation without changing the consumers of your class.

Just because there's no point at this time doesn't mean you should discard the getter/setter. It might be necessary in the future - thus the general rule to wrap it.

I'm coming from a primarily application programming background where we actually reuse our objects and code - a lot - whereas with game programming you tend to use and define it once, but I think the rule is a good one for general use.


In all areas of programming, get/set tuples are a code smell. They don't do any useful work because they don't abstract anything. If they actually do something, then they are very poorly named mutators.

It doesn't make sense to add abstraction you don't need to software. You can always do more work and add more abstraction, it's a run-away train scenario.

If you do need to change the behavior of the get/set later, you've violated interface contract and it's version should be bumped - this is a significant change to the design. Not compiling might be a good thing, it makes you review the code and ensure it will still work correctly with the new behavior.

All modern C++ compilers have a property extention to make get/set function transparent and a simple template adaptor can turn a member pointer into a functor (e.g. mem_accessor(&Circle::x) ).

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!