Sign in to follow this  
WindScar

[C++] Universal get() function.

Recommended Posts

Question in comment inside code:
class guy
{
   public:
   foo(int _a)
     : a(_a)
   {
   }

   get() //How to write that function so main() will input like shown below?

   private:
   int a;
}

int main()
{
   guy(1553);
   std::cout << guy.get(a); //Note it's not geta(), it's get(a), should work for any get(variable_name)
   return 0;
}


Desired input:
Quote:
1553

Share this post


Link to post
Share on other sites
C++ has no built in mechanism for this. There are various ways to emulate this behavior, but the details depend on what your exact needs are.

For more info on the subject, Google 'c++ reflection'.

Share this post


Link to post
Share on other sites
Doesn't a generic get() method defeat the purpose of making members private? If I want to change the internal implementation of my class in the future, code that uses get() would break, even if I leave my public interface unchanged.

Share this post


Link to post
Share on other sites
Thanks for the answers, but I do have reasons. The get() is just an example so you know what I want, so I don't have to explain the entire reason. If I can manage to make it work, I can also:

1. Simplify the parameters call when many variables have default values.
EG: Being able to call: bullet(speed=4) instead of bullet(0,0,4), when the middle 2 variables are, for exemple, it's position and their defaults are 0.

2. Be able to make a sort function to my container that sorts it's contained objects from one of it's variables, example:

container<bullet> bullets(bullet(0,0,3), bullet(20,1,4), (4,3,1));
bullets.sort(speed,1); //sort by speed asc
bullets.sort(x,0); //sort by x desc

3. Be able tell a function what object to create. Example:

class sweetiesFabric { blabla };
class chokobunny { blabla };
class goodcake { blabla };
sweeties_fabric_obj.create(chokobunny);
sweeties_fabric_obj.create(goodcake);

So I tell the fabric both to create a chokobunny object and a goodcake object. I suppose it can be done with a switch function, but then the function would have to be updated for every new class created and I suppose that goes against the good coding rules.

...

And, also, the get() function proposed won't violate the private as it is supposed to return just a copy of the variables.

Share this post


Link to post
Share on other sites
Quote:
Original post by WindScar
But why it doesn't? Mysql for example got "sort obj by var ASC" and is great, so I don't se reasons for ommiting that possibility.


Speed. C++ is build for speed. Reflection systems always require some kind of class metadata and have an effect on performance.

Share this post


Link to post
Share on other sites
Because if it was like SQL, it would be like SQL and not C++.

I think you might be enlighened by doing some research about the basic principles behind the design (*) of C++. It is not quite the kitchen sink it appears at a glance.

You might be interested in C#, which includes certain high level features like "LINQ" which appears similar to SQL, and because it allows refection would make it a lot easier to implement some of the stuff you are talking about. Or a language like Ruby, which again makes it relatively easy to do such things.

* its there somewhere

Share this post


Link to post
Share on other sites
Quote:
Original post by geolycosa
Quote:
Original post by WindScar
But why it doesn't? Mysql for example got "sort obj by var ASC" and is great, so I don't se reasons for ommiting that possibility.


Speed. C++ is build for speed. Reflection systems always require some kind of class metadata and have an effect on performance.


Not necessarily. C++'s mantra is "you don't pay for what you don't use", not "speed at all costs". If Windscar's hypothetical feature could be implemented in such a way that programs that didn't use it wouldn't require any overhead then "speed" shouldn't be an issue.

The lack of new uses for existing keywords and symbols would be an impediment however, I don't think the committee even consider ideas that don't redefine keywords we know, love and understand into things were any original semantic meaning is lost.

Share this post


Link to post
Share on other sites
Now that you know those can't be done the way you want to, this is how they would be in C++:

Quote:

1. Simplify the parameters call when many variables have default values.
EG: Being able to call: bullet(speed=4) instead of bullet(0,0,4), when the middle 2 variables are, for exemple, it's position and their defaults are 0.

bullet(speed=4) means that you know the name of the variable. If you know the name of the variable, then you defeat the purpose of private scoping - which is to encapsulate private fields so that they may change without breaking any user code. As such, simply make the variable a public variable (thus it becomes part of the public interface, which shouldn't change in a good design).

someBullet.speed = 4; // same effect via public variables


Quote:

2. Be able to make a sort function to my container that sorts it's contained objects from one of it's variables, example:

container<bullet> bullets(bullet(0,0,3), bullet(20,1,4), (4,3,1));
bullets.sort(speed,1); //sort by speed asc
bullets.sort(x,0); //sort by x desc


We do this in C++ with predicates:

struct speedPred
{
bool operator()(const bullet &a, const bullet &b)
{
return a.speed < b.speed;
}
};
std::sort(bullets.begin(), bullets.end(), speedPred());

// same idea for anything else


Quote:

3. Be able tell a function what object to create. Example:

class sweetiesFabric { blabla };
class chokobunny { blabla };
class goodcake { blabla };
sweeties_fabric_obj.create(chokobunny);
sweeties_fabric_obj.create(goodcake);

This is done via templates.

sweeties_fabric_obj.create<chokobunny>();

Except that it probably won't solve the problem you're looking to solve once you learn about how templates work, but I'll leave that for later.

Quote:

And, also, the get() function proposed won't violate the private as it is supposed to return just a copy of the variables.

It violates private because you know the name of the private variable, which you shouldn't. Private isn't about modification, it's about encapsulation.

Share this post


Link to post
Share on other sites
Just read something about reflective programming and that seem just a awesome idea, so sad C++ doesn't provide suppor to it.

But reflective goes as far as changing code blocks in runtime. I just want a way to send a class type to a function call and nothing else so it's more natural than having a new version of the function for every new class I create. There should be a way in C++.



@nullsquared
Quote:

Now that you know those can't be done the way you want to, this is how they would be in C++:

Quote:

1. Simplify the parameters call when many variables have default values.
EG: Being able to call: bullet(speed=4) instead of bullet(0,0,4), when the middle 2 variables are, for exemple, it's position and their defaults are 0.

bullet(speed=4) means that you know the name of the variable. If you know the name of the variable, then you defeat the purpose of private scoping - which is to encapsulate private fields so that they may change without breaking any user code. As such, simply make the variable a public variable (thus it becomes part of the public interface, which shouldn't change in a good design).

someBullet.speed = 4; // same effect via public variables



Yes, but now that I think about it, maybe it would be better if you could just expose a set "name" of classes. For example, a class "guy" with thousands of variables could expose just "name", "age" and "sex", wich would semantically mean "I got a name, i got a age, and i have a sex". That's not private info. So someone would later be able to call: "guy, give me your name" (guy.get(guy::name)) or "guy, give me your age" (guy.get(guy::sex)).

Quote:

Quote:

2. Be able to make a sort function to my container that sorts it's contained objects from one of it's variables, example:

container<bullet> bullets(bullet(0,0,3), bullet(20,1,4), (4,3,1));
bullets.sort(speed,1); //sort by speed asc
bullets.sort(x,0); //sort by x desc


We do this in C++ with predicates:

struct speedPred
{
bool operator()(const bullet &a, const bullet &b)
{
return a.speed < b.speed;
}
};
std::sort(bullets.begin(), bullets.end(), speedPred());

// same idea for anything else


But then I would have to write another function for every new variable I want bullet to be able to be sorted from, wich would be almost a copy from the previous function. In the end I would have thousand of functions that are just the same thing, when I could just call container.sort(speed,asc).


Quote:

Quote:

3. Be able tell a function what object to create. Example:

class sweetiesFabric { blabla };
class chokobunny { blabla };
class goodcake { blabla };
sweeties_fabric_obj.create(chokobunny);
sweeties_fabric_obj.create(goodcake);

This is done via templates.

sweeties_fabric_obj.create<chokobunny>();

Except that it probably won't solve the problem you're looking to solve once you learn about how templates work, but I'll leave that for later.

Of course, stupid from my part - I actually wanted to mean a way to store the object type in a variable and then send it to the fabric. For example:
class goodcake;
class guyWhoWantsCake;
guyWhoWantsCake guy(goodcake);
fabric.createCake(guy.getWantedCake());



So I know it can't be done in C++ but what do you guys think about the concept?

[Edited by - WindScar on February 12, 2010 4:09:48 PM]

Share this post


Link to post
Share on other sites
Quote:
There should be a way in C++.
Should a minivan be able to go from 0 to 60 in 6 seconds? Should a high-performance sports car be able to comfortably seat a family of five?

Different languages have different characteristics, strengths, and weaknesses, and some are more applicable to certain problem domains than others. Fortunately there's a lot of languages to choose from, so if C++ doesn't offer the features you need, you have a lot of other options.
Quote:
I just want a way to send a class type to a function call and nothing else so it's more natural than having a new version of the function for every new class I create.
I'm not sure what you mean by 'send a class type to a function call', but for what it's worth, there are a lot of ways to avoid code duplication in C++ (such as using templates), so I wouldn't assume that the only to solve the problems you're trying to solve is to write a lot of duplicate code.

Share this post


Link to post
Share on other sites
But that's just one thing I need, it doesn't justify changing the entire language as I'm already used to C++ and everything else is fine.

I think I know how I can express myself better: the same way we can store pointer to functions, I want to store like a pointer to a class so I can know in runtime what class to work on. That's it, basically. If it can't be done, how can it be emulated?

Share this post


Link to post
Share on other sites
Have you looked into using templates?

You don't even need templates, you can go with the manual factory option:

class base { virtual ~base(); };

class chokobunny : public base { blabla };
class goodcake : public base { blabla };

class sweetiesFabric {
base *create(const std::string &type)
{
if(type == "chokobunny") {
return new chokobunny();
} else if(type == "goodcake") {
return new goodcake(args);
} else {
/* handle type not found error */
}
}

// later

base *base = sweeties_fabric_obj.create("chokobunny");
base * base = sweeties_fabric_obj.create("goodcake");


It may not be glamorous, but not all code has to be.

Share this post


Link to post
Share on other sites
Yes I just covered the reason I don't in my last post. Because it wouldn't allow me to store what type to be used in a variable for later use and because of obvious maintenance issues.

And now that I think about it, a pointer to a class wouldn't be enough also. I'm a bit lost in the concepts, I'll research and think about it then I come back when I'm done. But until them I would be really really thankful if someone post the said way to emulate that generic get() function because I'm sure if I see that code things will become cleaner. Thanking also keyworks to look for.

Share this post


Link to post
Share on other sites
C++ isn't expressive enough to write such a generic get function.

This is why game logic is often written in a scripting language like Lua that can be "embedded" inside the main C++ core. Writing such a generic get function in lua is trivial.

TBH if I had to do what you are talking about I would implement my objects as std::map<std::string, variant_type> (variant_type probably boost::variant or boost::any). At the end of the day you will have to accept that every language is limited, and what you are trying to do (in your OP) is impossible in C++. Something like the following is quite doable, and in some ways more flexible than what you were aiming for originally (variables don't need to be compile time constants, they could be generated at runtime or read from a file or quake-style console).

int main()
{
object guy;
guy["speed"] = 15;
std::cout << guy.get<int>("speed");
return 0;
}

Share this post


Link to post
Share on other sites
Quote:

Yes, but now that I think about it, maybe it would be better if you could just expose a set "name" of classes. For example, a class "guy" with thousands of variables could expose just "name", "age" and "sex", wich would semantically mean "I got a name, i got a age, and i have a sex". That's not private info. So someone would later be able to call: "guy, give me your name" (guy.get(guy::name)) or "guy, give me your age" (guy.get(guy::sex)).


...
public:
std::string name;
int age;
sex_t sex;

private:
// rest of members
...

What's your point? That's exactly what public does.

Quote:

But then I would have to write another function for every new variable I want bullet to be able to be sorted from, wich would be almost a copy from the previous function. In the end I would have thousand of functions that are just the same thing, when I could just call container.sort(speed,asc).

A little bit of magic:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cassert>

struct obj_t
{
int num;
std::string str;
obj_t(int num, const std::string &str): num(num), str(str) {}
};

template<typename T>
struct objPred
{
T const obj_t::*var;
objPred(T const obj_t::*var): var(var) {}
bool operator()(const obj_t &a, const obj_t &b) const
{
return a.*var < b.*var;
}
};

int main()
{
std::vector<obj_t> list;
list.push_back(obj_t(42, "abc"));
list.push_back(obj_t(12, "bca"));

// sort by "num" variable
std::sort(list.begin(), list.end(), objPred<int>(&obj_t::num));

assert(list[0].num == 12);
assert(list[1].num == 42);
}

Share this post


Link to post
Share on other sites
Quote:
really really thankful if someone post the said way to emulate that generic get() function

Technically:
std::map<std::string, boost::any> clazz;

// I think this would be the syntax
int age = clazz["age"].get<int>();


With this approach you don't even need C++ classes, since each map is an instance of aggregate members.

Share this post


Link to post
Share on other sites
Quote:
Original post by WindScar
But until them I would be really really thankful if someone post the said way to emulate that generic get() function because I'm sure if I see that code things will become cleaner. Thanking also keyworks to look for.


Like previously mentioned, that doesn't make sense. If you can do obj.get(obj_t::num), why can't you just do obj.num?

Emulation would work like so:

template<typename T>
T get(T obj_t::*var)
{
return this->*var;
}

int num = obj.get(&obj_t::num);

Share this post


Link to post
Share on other sites
While I'm still a bit confused, everything is becoming clearer now, thank you very much. And it is pretty easy to code, why people said otherwise? And the get is actually useless, but the sort isn't. Why people said otherwise? And even though get's useless, it could be useful if this was possible:


class Foo
{
public:
T get(T Foo::*var) { if (!locked) return var; }; //BTW I'm still trying to understand how that works.

visible-but-not-accessible:
int a, b, c, d, e, f, g, h, i, j;
bool locked;
}




As it would allow you to write the get function only once. Or not?


And about the stuff about storing a class pointer? I've figured out a use for it:

class Board : public Some_Thread_Base_Class
{
public:
void logic()
{
artwork->draw();
}

void setArtwork(class* classType)
{
if (!locked)
{
delete artwork;
artwork = new classType(); //classType being replaced by "Artwork" or a derived
}
}
private:
Artwork * artwork;
int flags;
}


How can that be coded as C++ doesn't allow this way?

Share this post


Link to post
Share on other sites
Quote:
Original post by WindScar
How can that be coded as C++ doesn't allow this way?


Google: "factory pattern"

Alternatively, look up polymorphism. However, this is a little bad because the object allocating memory is not in charge of freeing it. (factory might be a little better)


class BaseArt
{
virtual ~BaseArt(); //important for base class destructor to be virtual
//since delete will be called with a base class pointer
};

class DragonArt : public BaseArt
{
};

class SnakeArt : public BaseArt
{
};




class MyDeal
{
public:
MyDeal(): mArt(NULL) {}

private:
void setArt( BaseArt *art )
{
if ( mArt )
delete mArt;
mArt = art;
}
BaseArt *mArt;
};




void myawesomefunction()
{
MyDeal theDeal;

theDeal->setArt( new DragonArt() );
}



-me

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this