Al resolver el problema que había en C++ con las macros cuando acceden a miembros de clases privada, todos los problemas asociados con las macros de preprocesador fueron eliminados. Esto se ha hecho aplicando el concepto de macros bajo el control del compilador al cual pertenecen. C++ implementa la macro como una función inline, lo que es una función real en todo sentido. Todo comportamiento esperado de una función ordinaria se obtiene con una función inline. La única diferencia es que una función inline se expande en el mismo sitio, como una macro de preprocesador, de modo que la cabecera de una llamada a función es eliminada. Por ello no debería usar macros (casi) nunca, solo funciones inline.
Cualquier función definida en el cuerpo de una clase es automáticamente inline, pero también puede hacer una función inline que no esté dentro del cuerpo de una clase, precediéndola con la palabra clave inline. De todos modos, para que esto tenga algún efecto, debe incluir el cuerpo de la función con la declaración, de otro modo el compilador tratará esa función como una declaración de una función ordinaria. Así:
inline int plusOne(int x);
no tiene ningún otro efecto que declarar la función (que puede o no obtener una definición inline después). La aproximación correcta proporciona el cuerpo de la función:
inline int plusOne(int x) { return ++x; }
Observe que el compilador revisará (como siempre lo hace), el uso apropiado de la lista de argumentos de la función y del valor de retorno (haciendo cualquier conversión necesaria), algo que el preprocesador es incapaz de hacer. Además, si intenta escribir lo anterior como una macro de preprocesador, obtendrá un efecto no deseado.
Casi siempre querrá poner las funciones inline en un fichero de cabecera. Cuando el compilador ve una definición como esa pone el tipo de la función (la firma combinada con el valor de retorno) y el cuerpo de la función en su tabla de símbolos. Cuando use la función, el compilador se asegura de que la llamada es correcta y el valor de retorno se está usando correctamente, y entonces sustituye el cuerpo de la función por la llamada a la función, y de ese modo elimina la sobrecarga. El código inline ocupa espacio, pero si la función es pequeña, realmente ocupará menos espacio que el código generado para una llamada a función ordinaria (colocando los argumentos en la pila y ejecutando el CALL).
Una función inline en un fichero de cabecera tiene un estado especial, dado que debe incluir el fichero de cabecera que contiene la función y su definición en cada fichero en donde se use la función, pero eso no provoca un error de definición múltiple (sin embargo, la definición debe ser idéntica en todos los sitios en los que se incluya la función inline).
Para definir una función inline, debe anteponer la palabra clave
inline
al nombre de la función en el momento
de definirla. Sin embargo, eso no es necesario cuando se
define dentro de una clase. Cualquier función que defina dentro
de una clase es inline automáticamente. Por ejemplo:
//: C09:Inline.cpp // Inlines inside classes #include <iostream> #include <string> using namespace std; class Point { int i, j, k; public: Point(): i(0), j(0), k(0) {} Point(int ii, int jj, int kk) : i(ii), j(jj), k(kk) {} void print(const string& msg = "") const { if(msg.size() != 0) cout << msg << endl; cout << "i = " << i << ", " << "j = " << j << ", " << "k = " << k << endl; } }; int main() { Point p, q(1,2,3); p.print("value of p"); q.print("value of q"); } ///:~
Listado 9.2. C09/Inline.cpp
Aquí, los dos constructores y la función
print()
son inline por defecto. Dese
cuenta de que usar funciones inline es transparente en
main()
, y así debe ser. El comportamiento
lógico de una función debe ser idéntico aunque sea inline (de
otro modo su compilador no funcionaría). La única diferencia
visible es el rendimiento.
Por supuesto, la tentación es usar declaraciones
inline
en cualquier parte dentro de la case porque
ahorran el paso extra de hacer una definición de método
externa. Sin embargo, debe tener presente, que la idea de una
inline es dar al compilador mejores oportunidades de
optimización. Pero, si declara inline una función grande
provocará que el código se duplique allí donde se llame,
produciendo código [FIXME:bloat] que anulará el beneficio de
velocidad obtenido (la única manera de descubrir los efectos
del uso de inline en su programa con su compilador es
experimentar).