Advertisement

C++ Macros

Started by August 02, 2000 05:18 PM
11 comments, last by jharkey 24 years, 4 months ago
Most people neglect this, but remember that macros are not functions in themselves. All the compiler does is replace the macro call with the actual text defined by the macro.

i.e.

#define MULTIPLY_BY_TWO(param) {param *= 2}

Whenever you call MULTIPLY_BY_TWO, it just replaces the code:

    int var;var += 4;MULTIPLY_BY_TWO(var);[/source]this is the same as[source]int var;var += 4;var *= 2;    


For this reason, I''ve had questions where people have used the wrong type of brackets, and not actually understood what their macro is in fact doing.

If you find yourself in that situation, consider using an inline function.



========
Smidge
www.smidge-tech.co.uk
========
--Mr Smidge
In most cases, macros are used when inline functions can be used. In those cases, you should use inline functions (like nearly everyone else said ).

Another problem with macros is that people use them to define constants:


#define MAX_CHARS 256

void main()
{
char array[MAX_CHARS];

// now use the array somehow
}



In those cases, you should use the C++ keyword "const", because it has stricter type-ing and can be used whenever #define-d constants can be used:


const int MAX_CHARS = 256;

void main()
{
char array[MAX_CHARS];

// now use the array somehow
}



However, there are some things that constants and inline functions cannot do. Macros are great for building really complex code out of simple words. This example builds a message map out of a few lines instead of many lines, and eliminates a lot of boring and redundant code (boring at least to the reader).

The example before macros:


LRESULT my_window::on_message(UINT ID, WPARAM wParam, LPARAM lParam)
{
switch( ID )
{
case WM_CLOSE:
return on_close();
case WM_PAINT:
return on_paint();
case WM_DESTROY:
return on_destroy();
default:
return window::on_message(ID, wParam, lParam);
}
}



That code simply calls the proper member function, depending on what message ID was sent to the on_message function. Boring. Let's look at macros. The first thing to do is to break the function down into common parts.

First, we have the beginning of the function, which is always: the name of the function, the opening brace, and the switch statement:


#define BEGIN_MESSAGE_MAP(class_name) LRESULT class_name::on_message(UINT ID, WPARAM wParam, LPARAM lParam) { switch( ID ) {



1 part down, two to go. Now we have the middle part, which is really the only thing that the function writer is concerned about:


#define ON_MESSAGE(ID, function_name) case ID: return function_name();



Finally, we have the end of the function and the default statement:


#define END_MESSAGE_MAP(base_class_name) default: return base_class_name::on_message(ID, wParam, lParam); } }



Now, once we have those macros, we can code the exact same example function like this:


BEGIN_MESSAGE_MAP(my_window)
ON_MESSAGE(WM_CLOSE, on_close)
ON_MESSAGE(WM_PAINT, on_paint)
ON_MESSAGE(WM_DESTROY, on_destroy)
END_MESSAGE_MAP(window)



_Much_ simpler, and the person writing the function can focus on what he needs that function to do, rather than getting caught up in how the switch statement works and when to call the base class version, etc.



- null_pointer
Sabre Multimedia


Edited by - null_pointer on August 7, 2000 8:26:38 AM
Advertisement
inline this.

        #define     VFuncTable(n)   virtual void *VF##n(void **params);  REGISTER_VFUNC(##n)class A : public Base{public:       A();     ~A();     VFuncTable(Method1);     VFuncTable(Method2);     VFuncTable(Method3);     static Base dummy;};class B : public A{public:     B();     ~B();     void     SetCallback(void *p(void **), DynamicClass n)      {            . . .     }};        



-goltrpoat


--
Float like a butterfly, bite like a crocodile.



Edited by - goltrpoat on August 7, 2000 8:58:22 AM
--Float like a butterfly, bite like a crocodile.

This topic is closed to new replies.

Advertisement