Hi,
For many years now the VC++ compiler has a very handy feature that none of the C++ programmer I have met knew about, so it may be worth writing about.
The feature is called as "virtual data members" in the Microsoft documentation and it is used extensively in COM programming. The interesting thing is not so much what it does, but what kind of problems it can help you solve very easily.
Suppose you have a class like the one shown below:
class Operation
{
int m_ZoomFactor;
public:
Operation():m_ZoomFactor(1){}
void DoSomething(){ --m_ZoomFactor; }
};
You have some member m_ZoomFactor that can take the value 0 among others. Many of your member functions are directly messing with m_ZoomFactor, like the DoSomething() member function.
But now your design has changed. Zero is no longer a permitted value. So you have to change the whole code to make sure that zero can in no way be assigned.
Now, wouldn't it be handy if you could put a data breakpoint to catch zero assignments. It would be nice, but your application is also performance critical and data breakpoints are slow, plus the application is run by testers as well, and they can't put such a breakpoint.
The next thing that comes to mind is to make a setter and a getter function for the zoom factor and then change all the code to use these functions. Nice but ugly and it takes time. What if the compiler could do all the work for you? That would be really nice! And in fact it can be done. Here is how:
class Operation
{
int m_ZoomFactor_;
__declspec( property(
get=GetZoomFactor,
put=SetZoomFactor) ) int m_ZoomFactor;
int GetZoomFactor(){ return m_ZoomFactor_; }
void SetZoomFactor(int newValue)
{
_ASSERT(newValue);
m_ZoomFactor_ = newValue;
}
public:
Operation():m_ZoomFactor_(1){}
// Original code of member functions remains unchanged.
void DoSomething(){ --m_ZoomFactor; }
};
By using __declspec property you tell the compiler to replace as appropriate all references to m_ZoomFactor with the getter or setter function. So, you can continue writing your program as before, and if by any chance you forget to check some code path that assigns zero, you will catch the offender on the spot, before the code runs astray, messes everything up and then leaves you staring at your monitor and wondering how did all the mess came about!
Needless to say, you can use this trick only for the debug build, so as to add some extra sanity checks (you cannot assign this value if the other data member has this value etc) and leave the release build working directly with the data members. The possibilities are endless!
Have Fun!
Dimitrios Staikos