 |
|
Page 1 of 1
|
[ 9 posts ] |
|
C++ permissions : creating read-only variables
Author |
Message |
byuu
|
 C++ permissions : creating read-only variables
So, one of the things sorely lacking in C++ is native support for permissions. Take *nix for instance, a file can be read-write to the owner, but read-only to others.
To work around that, the common answer is a get function, eg:
Another alternative is to name the variable p_value, and the read-only function value(). I hate both of these: many times, it makes the most sense to use the same name for both the variable and the read function, eg cartridge.name. I also don't want it to act like something it's not, eg requiring a special set() function to assign to the variable is out of the question. I've come up with a workaround: This abuses an issue with the C++ standard: for whatever reason, the following is not valid: ... but since compilers go out of their way to enforce it, it's very easy to trick them:
Another more legal alternative would be to #define PROPERTY(classname) and generate the property class inside a class definition.
But both of these methods have one obvious flaw: friends are not transitive. That is, no derived class can gain read-write access to a property defined in a base class, which is a problem for me as most of my processor classes use abstract base classes to define the interface.
So, I've run out of tricks here. Anyone think they can do something like the above, but with the ability to be inherited?
|
Thu Feb 19, 2009 6:33 pm |
|
 |
byuu
|

Not quite what I wanted (need set() to modify variables), but it does allow for proper inheritance, at least ...
And no compiler hacks / #defines / unnatural syntax.
 |  |  |  | Code: class property { public: template<typename T> class container;
protected: template<typename T> container<T>& set(container<T>&, const T);
public: template<typename T> class container { public: const T& operator()() const { return value; } container() : value() {} container(const T newValue) : value(newValue) {}
protected: friend container<T>& property::set<T>(container<T>&, const T); T value; }; };
template<typename T> property::container<T>& property::set(property::container<T> &p, const T value) { p.value = value; return p; }
class Cartridge : public property { public: container<bool> sdd1; container<const char*> name;
Cartridge() : sdd1(false), name("???") { set(name, "<none>"); } };
class Subcart : public Cartridge { public: void set_name(const char *newName) { set(name, newName); }
Subcart() { set(sdd1, true); set(name, "The Legend of Zelda"); } } cartridge;
int main() { printf("%d\n%s\n", cartridge.sdd1(), cartridge.name()); cartridge.set_name("A Link to the Past"); printf("%s\n", cartridge.name()); return 0; } |  |  |  |  |
|
Fri Feb 20, 2009 1:58 am |
|
 |
blargg
Regular
Joined: Thu Jun 30, 2005 1:54 pm Posts: 327 Location: USA
|
Deja-vu (done something very similar to this years ago, including the issue with friendship... did I give you my code a while back?). Two choices:
1) different names, everyone understands, no subtle problems, and you don't give C programmers more ammo as to why they hate C++.
2) complicated brittle template solution, but you give the language a good scolding and don't yield to this absolutely glaring omission that every single program would benefit greatly from.
Which you choose depends on your overall goals.
|
Fri Feb 20, 2009 2:43 am |
|
 |
byuu
|

I don't recall your solution, but then I'm very forgetful :(
I'd be very interested if you still have it lying around. Otherwise, I think I've mostly got it.
1. is certainly the easier and more standard way to go, but the naming conventions for it just make me sick:
bool isdd1, psdd1, p_sdd1, rw_sdd1, w_sdd1; //hungarian vomit :(
bool sdd1() const { return isdd1; }
bool sdd1;
bool has_sdd1() const { return sdd1; }
const char *get_name() ...
bool is_bsx_cart() ... //no consistency with prefixes
I also really don't want to declare both a variable and a function for every single property. A #define could sort of work, but would override the current public/protected/private setting for the class. And if only $ were a standard C++0x marker instead of a common extension, heh. That would really screw with people :P
2. with my first idea gives me beautiful syntax, but lacks derived class inheritance. Why, oh why can't you override friendship intransience? :(
Transience is the whole point of object-oriented programming, ugh.
2. with the second idea is great for inheritance, but it's basically replacing the specialized get() functions with specialized set() functions. But on the plus side, the set() function is one scope higher, so you still keep the same variable names ... and the headache should be on the internals, not on the external classes accessing it.
|
Fri Feb 20, 2009 3:39 am |
|
 |
blargg
Regular
Joined: Thu Jun 30, 2005 1:54 pm Posts: 327 Location: USA
|
If you have lots of information about the object, return a struct containing it:
Unless this is called really often, efficiency will not be a concern, socomplexity shouldn't be wasted on optimizing it. I recommend posting to comp.lang.c++, as you'll get more insight than here.
EDIT: A writeup and minimal code example (properties.cpp). I do find the general concept interesting.
|
Fri Feb 20, 2009 6:13 am |
|
 |
grinvader
ZSNES Shake Shake Prinny
Joined: Wed Jul 28, 2004 4:15 pm Posts: 5613 Location: PAL50, dood !
|
Not like I need more, it's already past critical mass.
_________________ 皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
|
Fri Feb 20, 2009 6:56 am |
|
 |
creaothceann
Seen it all
Joined: Mon Jan 03, 2005 5:04 pm Posts: 2302 Location: Germany
|
And that's why Delphi has properties.
_________________ vSNES | Delphi 10 BPLs bsnes launcher with recent files list
|
Fri Feb 20, 2009 8:37 am |
|
 |
byuu
|
I sort of do the same now, I just don't bother with making a copy of it (meaning it can be modified externally.) I wouldn't say I use this info a lot, but we can get rid of any potential copy overhead anyway:
An interesting read. I see you've hit the same template friend class problem. Didn't mention the transience issue though.
I wanted to offer a custom callback mechanism to detect reads / writes to give it more functionality, but I'm reminded of your advice to only add stuff when you need it, heh.
May be difficult to nest two types, though:
property_t< callback_t<int> > foo;
callback_t::get,set will probably want full access to the property_t. Granting that with friendship would create a loophole to avoid the read-only access.
I suppose it'd be best to just make the property::set(property_t&, const T&) function virtual:
if(&p == &property_1) ...
else if(&p == &property_2) ...
|
Fri Feb 20, 2009 7:10 pm |
|
 |
blargg
Regular
Joined: Thu Jun 30, 2005 1:54 pm Posts: 327 Location: USA
|

Yes, I didn't want to encourage premature optimization. But since it's been exposed, I'll add that this can even handle cases where some members are calculated only when info is called: The functions the property calls in the parent class take the property as a reference. Each property has a different type, so the parent functions get overloaded. The parent can either ignore the property parameter, or can use static functions and get the parent reference from the passed property, thus avoiding the useless 'this' parameter' (good for efficiency maniacs):  |  |  |  | Code: class Parent { public: PROPERTY(value_cached,int,foo); // uses set( foo_t, int ) PROPERTY(value_cached,int,bar); // uses set( bar_t, int ) private: int dependent; void set( foo_t&, int new_foo ); // could be made virtual static void set( bar_t& prop, int new_bar ); // avoids extra 'this' parameter };
void Parent::set( foo_t&, int new_foo ) { dependent = (dependent & 0xFF00) | new_foo; }
void Parent::set( bar_t& prop, int new_bar ) { prop.parent().dependent = (prop.parent().dependent & 0xFF) | (new_bar << 8); } |  |  |  |  |
The concept being discussed here goes beyond simple get/set properties, like the enter/exit one.
|
Fri Feb 20, 2009 8:49 pm |
|
|
|
Page 1 of 1
|
[ 9 posts ] |
|
Who is online |
Users browsing this forum: No registered users and 3 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum
|
|
 |
|