views:

1149

answers:

4

I have some code that has a dynamic-class system in C++ that has a member called GetClassName(), a rather harmless name one would imagine. However when included in a large project with Windows headers all hell broke loose. Apparently Windows uses a #define GetClassName (GetClassNameA or GetClassNameW) which screws up everything, and my virtual call tree became all messed up making me loose a day in stupid compiler debugging in the dark, trying to figure out what was wrong.

So besides the point that I'm cursing Microsoft for using such a horribly easy to clash name for a #define (I mean someone should honestly be shot for this!) I'm asking for 3 purposes.

  1. What's another good name for GetClassName() ?
  2. Is there anyway to fix this, so in the future, other developers of my code base won't suffer similar fate
  3. And for posterity when someone else encounters this similarly inexplicable error
+4  A: 
  1. ClassGetName()
  2. #undef GetClassName
  3. WinAPI is a C API. No namespaces. Some other platforms try to mitigate this by prefixing all symbol names, but eventually that falls apart as well. Best bet: if you're writing code that doesn't depend on the Windows Platform SDK headers, then don't #include them.
Shog9
My code doesn't depend on any windows header, and it passes unit tests on its own, however when client code used them, BAM, errors happened. Which was a total mystery to me until I tracked down the windows header issue :(
Robert Gould
Perhaps they're using pre-compiled headers that include the PSDK headers? A great idea, when you're building lots of code that uses those headers, since it speeds up build times considerably... but worth disabling for files that don't.
Shog9
Changing the include order on the client side is a possible solution to mitigate the problem. But if they include your file in a .h of their own they will have to watch their whole include chain... Changing your name may be easier for everyone.
VirtualBlackFox
+2  A: 

GetWindowClassName perhaps? In reality GetClassName is not a bad name for this API as it relates to window classes. The real problem is that it's a C API declaration and C declarations have no way to introduce a re-usable declaration which doesn't pollute the global namespace.

This is much more a failing of the C language than microsoft.

JaredPar
+2  A: 

The Windows API is chock full of macros with clean names that expand to function names with a suffix indicating ASCII/UTF-16, dependent on build options. It would have been nice if they prefixed everything with "W32" or similar (a la "NS" on OS X), but they chose not to presumably to keep the API "clean".

Since it's a lot easier to change your code than their API, here are a few suggestions:

1) Learn the Windows API (it's actually not that big!), or at least become familiar with MSDN so that you can look for name clashes when you encounter inexplicable program flow.

2) Use explicit scope resolution in your code where you can (MyClass::GetClassName()). Unfortunately, this will break virtual function dispatch, so be careful with this.

3) Use a different naming convention in your code. MS always uses CamelCase, so you won't clash if you pick some other convention (get_class_name(), getClassName(), etc.).

4) Personally, I hate naming my getters & setters "GetX()" and "SetX()", but prefer to lean on the overloading mechanism and use "xtype X() const" for getters and "void X(xtype newval)" for setters. Your mileage may vary, but I find it cleaner & the get/set is obvious from the arguments. Obviously you have to be careful if you're using default arguments.

Good luck!

Drew Hall
I strongly agree with point 4, but policy dictates my naming. I really find it to be the prettiest api.
Robert Gould
I also like #4. Screw policy. "It's not a setter - it's a putter!"
Shog9
+1  A: 

I would rename the method.

Of course one can say

#include <windows.h>
#undef GetClassName

but it is not clean, users of one's code should remember to write ::GetClassNameW when they call win32 function.

One can provide GetClassNameA and GetClassNameW methods in his class, but it's plain ugly.

I see two approaches : either lengthen or shorten the name:)

1) add a prefix for all functions in the subsystem, f.e TI_ (for type info):

TI_GetClassName() 
TI_GetBaseClass() 
TI_IsDerivedFromClass()
etc

2) or put them into some IClass interface

interface IClass {
GetName();
GetBase(); 
IsDerivedFrom();
etc

and return that interface from single method,
so that GetClassName() becomes

GetClass()->GetName()
eugensk00
Idea number 2 is quite good, didn't think about that one.
Robert Gould