NB Esta no es una pregunta sobre cómo usar las funciones en línea o cómo funcionan, sino por qué se hacen de la forma en que están.
La declaración de una función miembro de clase no necesita definir una función como inline
, es solo la implementación real de la función. Por ejemplo, en el archivo de encabezado:
struct foo{
void bar(); // no need to define this as inline
}
Entonces, ¿por qué la implementación en línea de una función de clases tiene que estar en el archivo de encabezado? ¿Por qué no puedo poner la función en línea en el .cpp
archivo? Si intentara poner la definición en línea en el .cpp
archivo, obtendría un error en las líneas de:
error LNK2019: unresolved external symbol
"public: void __thiscall foo::bar(void)"
(?bar@foo@@QAEXXZ) referenced in function _main
1>C:\Users\Me\Documents\Visual Studio 2012\Projects\inline\Debug\inline.exe
: fatal error LNK1120: 1 unresolved externals
inline
aparece en una definición pero no en una declaración previa y viceversa . Si es así, esto puede ayudar: stackoverflow.com/questions/4924912/…Respuestas:
La definición de una
inline
función no tiene que estar en un archivo de encabezado pero, debido a la regla de una definición ( ODR ) para funciones en línea, debe existir una definición idéntica para la función en cada unidad de traducción que la use.La forma más sencilla de lograr esto es poniendo la definición en un archivo de encabezado.
Si desea poner la definición de una función en un solo archivo fuente, no debe declararla
inline
. Una función no declaradainline
no significa que el compilador no pueda alinear la función.Si debe declarar una función
inline
o no, suele ser una elección que debe tomar en función de la versión de las reglas de una definición que tenga más sentido seguir; agregarinline
y luego ser restringido por las restricciones subsiguientes tiene poco sentido.fuente
+1
de mi parte!Hay dos formas de verlo:
Las funciones en línea se definen en el encabezado porque, para insertar una llamada de función, el compilador debe poder ver el cuerpo de la función. Para que un compilador ingenuo haga eso, el cuerpo de la función debe estar en la misma unidad de traducción que la llamada. (Un compilador moderno puede optimizar en todas las unidades de traducción, por lo que una llamada de función puede estar insertada aunque la definición de la función esté en una unidad de traducción separada, pero estas optimizaciones son costosas, no siempre están habilitadas y no siempre fueron compatibles con el compilador)
las funciones definidas en el encabezado deben marcarse
inline
porque de lo contrario, cada unidad de traducción que incluye el encabezado contendrá una definición de la función, y el enlazador se quejará de múltiples definiciones (una violación de la Regla de una definición). Lainline
palabra clave suprime esto, lo que permite que varias unidades de traducción contengan definiciones (idénticas).Las dos explicaciones realmente se reducen al hecho de que la
inline
palabra clave no hace exactamente lo que esperarías.Un compilador de C ++ es libre de aplicar la optimización en línea (reemplazar una llamada de función con el cuerpo de la función llamada, ahorrando la sobrecarga de la llamada) en cualquier momento que quiera, siempre que no altere el comportamiento observable del programa.
La
inline
palabra clave hace que sea más fácil para el compilador aplicar esta optimización, al permitir que la definición de la función sea visible en múltiples unidades de traducción, pero usar la palabra clave no significa que el compilador tenga que alinear la función, y no usar la palabra clave no lo hace. prohíbe al compilador insertar la función.fuente
Este es un límite del compilador de C ++. Si coloca la función en el encabezado, todos los archivos cpp donde se puede insertar pueden ver la "fuente" de su función y el compilador puede realizar la inserción. De lo contrario, el enlazador debería realizar la inserción (cada archivo cpp se compila en un archivo obj por separado). El problema es que sería mucho más difícil hacerlo en el enlazador. Existe un problema similar con las clases / funciones de "plantilla". El compilador debe crear una instancia de ellos, porque el enlazador tendría problemas para instanciarlos (crear una versión especializada de). Algún compilador / enlazador más nuevo puede hacer una compilación / enlace de "dos pasadas" donde el compilador hace una primera pasada, luego el enlazador hace su trabajo y llama al compilador para resolver cosas no resueltas (en línea / plantillas ...)
fuente
La razón es que el compilador tiene que ver la definición para poder colocarla en lugar de la llamada.
Recuerde que C y C ++ usan un modelo de compilación muy simplista, donde el compilador siempre ve solo una unidad de traducción a la vez. (Esto falla para la exportación, que es la razón principal por la que solo un proveedor lo implementó).
fuente
La
inline
palabra clave c ++ es engañosa, no significa "en línea esta función". Si una función se define como en línea, simplemente significa que se puede definir varias veces siempre que todas las definiciones sean iguales. Es perfectamente legal que una función marcadainline
sea una función real a la que se llama en lugar de insertar código en el punto donde se llama.Es necesario definir una función en un archivo de encabezado para las plantillas, ya que, por ejemplo, una clase con plantilla no es realmente una clase, es una plantilla para una clase de la que puedes hacer múltiples variaciones. Para que el compilador pueda, por ejemplo, hacer una
Foo<int>::bar()
función cuando usa la plantilla Foo para crear una clase Foo , la definición real deFoo<T>::bar()
debe estar visible.fuente
inline
(ni no declararlainline
garantiza que no estará en línea).Sé que este es un hilo antiguo, pero pensé que debería mencionar la
extern
palabra clave. Recientemente me encontré con este problema y lo resolví de la siguiente maneraAyudante.h
Helper.cpp
fuente
Porque el compilador necesita verlos para integrarlos . Y los archivos de encabezados son los "componentes" que se incluyen comúnmente en otras unidades de traducción.
fuente
Funciones en línea
En C ++, una macro no es más que una función en línea. Así que ahora las macros están bajo el control del compilador.
El código de la función Inline se reemplaza en el lugar donde se llama, por lo que reduce la sobrecarga de la función de llamada.
En algunos casos, la función Inlining no puede funcionar, como
Si se usa una variable estática dentro de la función en línea.
Si la función es complicada.
Si la llamada de función recursiva
Si la dirección de la función se toma implícita o explícitamente
La función definida fuera de la clase como se muestra a continuación puede volverse en línea
La función definida dentro de la clase también se vuelve en línea
Aquí las funciones getSpeed y setSpeed se convertirán en inline
fuente