0

Ok so I'm learning to program for multiple platforms and I saw that lots of includes/libraries use Macros to tell the compiler which functions to call on specific platforms.

So I went ahead and defined the following:

#if defined _WIN32 || defined _WIN64
    #define Close(Handle) CloseHandle(Handle)
#else
    #define Close(Handle) close(Handle)
#endif

But then my Socket class has the following member function:

Socket::Close()
{
    //Close socket and clean up..
}

When I do the following:

Socket sock(Port, LocalHost);
sock.Close();

I get:

error: 'class Socket' has no member named 'CloseHandle'
     #define Close(Handle) CloseHandle(Handle)
                           ^
note: in expansion of macro 'Close'
       sock.Close();
            ^

Any ideas how I can fix it or should I just get rid of the Close and make it a typedef?

Brandon
  • 22,723
  • 11
  • 93
  • 186
  • 4
    macro do not "override" anything. all it does is a simple text (or token) replacement. – Elazar May 26 '13 at 18:29
  • Hmm but why is it replacing a Class Member though :S I used the word overriding wrong. I meant that its taking place of my class member. – Brandon May 26 '13 at 18:30
  • 2
    Because it's just a text replacement! Macros don't know anything about classes (or indeed anything about the C/C++ grammar). – Oliver Charlesworth May 26 '13 at 18:30
  • the preprocessor knows nothing about classes and memers. all he knows is strings and tokens. – Elazar May 26 '13 at 18:31
  • 2
    [Because macros are evil.](http://stackoverflow.com/questions/14041453/why-preprocessor-macros-are-evil-and-what-is-the-real-alternative-c11) – Sion Sheevok May 26 '13 at 18:33
  • Is the close macro meant for socket class, or is meant for something else and you just happen to have this Socket class with the same named function which you don't want to be replaced? – mclaassen May 26 '13 at 18:38
  • The macro was for something else and they weren't supposed to clash. I fixed it by doing: http://pastebin.com/2J575NZN – Brandon May 26 '13 at 18:41
  • You don't need to check `|| defined _WIN64` as `_WIN32` is defined even when building in 64bit. Reference: http://msdn.microsoft.com/en-us/library/b0084kay.aspx – moala Jan 07 '14 at 17:39

2 Answers2

2

The simplest solution would be just to use another name for you macro.

But that's not the right thing to do: on some platforms, you will want more complex logic to perform a platform-specific action (just for example, you could need to perform something like 'flush' before 'close'). So it would be better to isolate your #ifdef inside a function:

void Close(Handle handle) {
#if defined _WIN32 || defined _WIN64
    CloseHandle(handle);
#else
    close(handle);
#endif
}

Socket::Close()
{
    //Close socket and clean up..
    ::Close(...);
}

It would be even more elegant if you defined an abstract class (Environment) that provides an interface to all system-specific actions, and write an implementation of the class (in a subclass - WindowsEnvironment, PosixEnvironment) for each concrete platform. The instance of the class can be a singleton which is globally accessible, and selecting the proper environment could be performed without macros at all - just by compiling the right source file in the project.

nullptr
  • 11,008
  • 1
  • 23
  • 18
0

You should create cross-platform interface for your class. For example, you need to create close() method. This method should exist on all platforms. If implementation differs on different platforms, you should use macros to add separate implementation for each platform. It should be done in cpp file.

.h file:

void close(Handle handle);

.cpp file:

void Socket::close(Handle handle) {
  #if defined _WIN32 || defined _WIN64
    CloseHandle(handle);
  #else
    close(handle);
  #endif
}
Pavel Strakhov
  • 39,123
  • 5
  • 88
  • 127
  • But socket is already cross platform. The problem was my macro didn't allow me to call the Close function of the socket class because the compiler was replacing it with the Macro's expansion. – Brandon May 26 '13 at 18:38
  • Then do not define `Close` macro. You don't need it. – Pavel Strakhov May 26 '13 at 18:40
  • I think the answer is saying don't just globally replace all calls to Close with the macro, but instead use an #ifdef to conditionally call the different method you need in those places in your code where you need to call one or the other. – mclaassen May 26 '13 at 18:42
  • K I'll accept it because its the only answer and what you said above makes sense.. but I fixed it by doing: http://pastebin.com/2J575NZN – Brandon May 26 '13 at 18:43