 |
|
 |
this method is very good ,it give me some hint in db encapsulation.
-- modified at 8:33 Tuesday 22nd August, 2006
ztf
|
|
|
|
 |
|
 |
Obviously, every implementation of properties with a natural field-like syntax will incur in the same 4-byte penalty. It seems to me the author considered this overhead Ground Zero and what he meant by “no memory overhead” is that this implementation doesn’t store any additional information such as the owner this pointer or the pointers to the get/set functions.
I don’t think trying to add new features such as properties is to dislike C++, actually one of the reasons I like C++ is because you can do this sort of things. Try adding properties to Java for example.
Are macros bad? I think “dangerous” is a better word to describe them but again that’s something every C++ should know before trying to extend the language or reading an article like this one.
I think the author did a good job because it goes straight to the point in just a few lines of pure C++ code.
PD: I was about to post a similar article myself but luckily I ran into this first, it was pretty much the same thing! with the same name conventions and the offsetof macro used in the exact same way
|
|
|
|
 |
|
 |
What is so hard about writing a your own get/set methods and declaring a member variable???
I mean seriously... This is one of the most convoluted and stupid ideas I have ever seen in C++. Have fun expanding tree branches in the Debugger's watch window.
Am I missing something? Does this do anything more interesting than just give you a get/set method?
Does it give us some sort of magic intro-spection to automatically build up property pages? (Such pages are usually useless anyway, with lots of meta-data to explain HOW to edit your property).
|
|
|
|
 |
|
 |
What is hard is not writing of set/get methods, but using set/get methods. By using properties, the interface to a class is simplified, and the programmer needs to remember less things.
|
|
|
|
 |
|
 |
Okay, so as I thought, this package is useless.
What is so hard about remembering to put () after the name of the property?
|
|
|
|
 |
|
 |
Hey armentage, I don't like your tone!
You should change the way you talk to people, or they will think you're a programming snob.
Judging by the way you phrased your messages, it's likely you're not familiar with the C# language at all.
Properties are one of the coolest new programming languages inventions. In fact, most programmers I know who use both C++ and C# wish they had properties easily available in C++ as well.
I myself have moved away from programming with macros, in exchange for template-based coding practices, but I don't think there's anything inherently wrong with using macros. If it works for you, use it.
Since I feel properties are a great idea, I ended up writing my own template-based "Property" class. In this particular case, for properties, templates work better because not only is it type-safe, you can also have 'read-only' and 'write-only' variations. Another reason not to use macros in this particular case is that the macro is simply too big.
|
|
|
|
 |
|
 |
1) My tone is my tone.
2) I know all about properties and C#
3) I think macros and templates are both great, and I use both when it's appropriate.
4) I don't see how wrapping every member variable of my class with a whole new class is any better than writting accessors by hand.
class MyClass {
int m_myInt;
int m_myComplexInt;
public:
int myInt() { return m_myComplexInt; }
int& myInt() const { return m_myComplexInt; }
int getMyComplexInt() const { return m_myComplexInt; }
void setMyComplexInt(int newVal) { do something fancy here }
}
Given how simple the... simple cases are, why obfuscate things with a macro? And the moment you have something fancier than a simple return of the data in question, All the extra typing the macro package saved you is moot anyway.
Notice that I did a return of the actual int and not a reference to it. Can your macro package do that? Or will I have to have a REF_PROPERTY and VALUE_PROPERTY? How about by pointer? const pointer? The list goes on and on, and the cases I can use this macro package dwindle.
-- modified at 17:09 Tuesday 27th December, 2005
|
|
|
|
 |
|
 |
A member-variable is not a property, and writing getter/setter wrapper functions don't change that fact.
I still believe you don't understand what properties are, or how to use them.
|
|
|
|
 |
|
 |
Properties are nothing new. COM objects have had them for years, and Microsoft's compiler has supported the __declspec(property) directive since version 4.0 of Visual C++.
Properties (C/C++ that is ... they are virtually required for COM objects) add nothing in the way of flexibility nor readability to the code. All they do is satisfy a programmer's preferences. There is nothing wrong with that, but don't make it sound like they are the greatest thing since sliced bread.
Macros can be useful when well-defined. Many times, however, programmers define macros out of laziness (where a template or inline function would work much better).
Overall, this article is okay. It provides a way for cross-platform code to include properties. However, if you are using Win32, the __declspec directive is much more efficient.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
 |
|
 |
try smth like that:
class A{
public:
property<int, A::get_data, A::set_data > data;
int get_data(){ return data.m_data; }
void set_data(int val){ data.m_data = val; }
A():data(this){}
};
|
|
|
|
 |
|
 |
What you are proposing is not possible, because the class type that owns 'get_data' and 'set_data' must be part of the 'property' class.
|
|
|
|
 |
|
 |
template<class T, class V>
struct property{
V _value;
int (T::*_get)();
void (T::*_set)(int);
T* _this;
property(T* this_, int (T::*get)()=0, void(T::*set)(int)=0 ):_get(get),_set(set),_this(this_){}
operator int(){ return _get?(_this->*_get)() : _value; }
void operator=(int i){ if(_set)(_this->*_set)(i); else _value = i; }
};
struct A{
property<A,int> data;
int get_data(){return data._value;}
void set_data(int i){ data._value = i;}
A():data(this,&A::get_data/*, &A::set_data*/){}
};
int main(){
A a;
a.data = 5;
int i = a.data;
return 0;
}
-- modified at 8:27 Wednesday 21st December, 2005
|
|
|
|
 |
|
 |
template<class T, class V, V (T::*_get)(), void (T::*_set)(V)>
struct property{
V _value;
T* _this;
property(T* this_):_this(this_){}
operator V(){ return (_this->*_get)(); }
void operator=(V i){ (_this->*_set)(i);}
};
struct A{
int get_data(){return data._value;}
void set_data(int i){ data._value = i;}
property<A,int,&A::get_data,&A::set_data> data;
A():data(this){}
};
int main(){
A a;
a.data = 5;
int i = a.data;
return 0;
}
-- modified at 8:46 Wednesday 21st December, 2005
|
|
|
|
 |
|
 |
VC++ 6.0 : error C2027: use of undefined type 'A'
|
|
|
|
 |
|
 |
So, what? VC++ 6.0 is out-of-date for a long time.
Use VC 8 or last GCC
|
|
|
|
 |
|
|
 |
|
 |
Indeed, and I was not aware of it. Although my code is generic for C++, not for MFC.
|
|
|
|
 |
|
 |
Mine is also generic. I just use MFC as example of its use.
|
|
|
|
 |
|
 |
Your's is specific to Microsoft's compiler. This article offers a similar ability that (theoretically) can be used on multiple platforms and with any ANSI-compliant compiler.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
 |
|
 |
The 4 bytes per property is not really something that you can ignore.
If you stick the member directly in the nested class you don't get any additional overhead. Something like below. The changes are a little helper macro to deref the nested class in the set property call and the friendship is now mutual. Only downside is that the properties are not members anymore and hence require different intialisation.
You get similar optimisation to the original.
#define CLASS(NAME)\
typedef NAME ClassType;
#define SETPROPERTY( NAME, VALUE )\
NAME.m_ = VALUE;
#define PROPERTY(TYPE, NAME)\
private:\
class NAME##_class\
{\
public:\
operator TYPE () const\
{\
return m_;\
}\
TYPE operator = (TYPE val)\
{\
get_owner_object()->set_##NAME(val);\
return val;\
}\
private:\
ClassType *get_owner_object() const\
{\
ClassType *owner_object = (ClassType *)((char *)this - offsetof(ClassType, NAME));\
return owner_object;\
}\
const ClassType *get_owner_object_const() const\
{\
return get_owner_object();\
}\
friend class ClassType;\
TYPE m_;\
};\
friend class NAME##_class;\
public:\
NAME##_class NAME;
class Foo
{
public:
Foo()
{
data = 0;
}
CLASS(Foo);
PROPERTY(int, data);
private:
void set_data( int v )
{
SETPROPERTY( data, v*2 );
}
};
|
|
|
|
 |
|
 |
Clever trick, indeed. But it has two drawbacks:
1) it is not generic enough: it does not cover virtual properties. This could be rectified by having different macros for different property characteristics: read/write, virtual/non-virtual.
2) the internal property type may be different. Again, this can be rectified by specifying an internal as well as an interface type.
4 bytes per property is not that much of a problem, in my opinion. Let's say the average GUI app has 100 widgets, where each widget has 20 properties. The extra space needed would be 8K.
And isn't there a compiler option in most compilers not to generate extra space for empty members?
|
|
|
|
 |
|
|
 |
|
|
 |
|
 |
I disagree. C++ is a highly flexible language, and allows programmers to use it in the ways they feel comfortable. If someone likes properties, he can use them or not - it is a matter of choice. The great thing about C++ is that we do have the power to choose.
My programming blahblahblah blog. If you ever find anything useful here, please let me know to remove it.
|
|
|
|
 |
|
|
 |