Buscar..


Función multiplicada definida

La consecuencia más importante de la regla de definición única es que las funciones no en línea con enlace externo solo deben definirse una vez en un programa, aunque se pueden declarar varias veces. Por lo tanto, tales funciones no deben definirse en encabezados, ya que un encabezado puede incluirse varias veces desde diferentes unidades de traducción.

foo.h :

#ifndef FOO_H
#define FOO_H
#include <iostream>
void foo() { std::cout << "foo"; }
void bar();
#endif

foo.cpp :

#include "foo.h"
void bar() { std:: cout << "bar"; }

main.cpp :

#include "foo.h"
int main() {
    foo();
    bar();
}

En este programa, la función foo se define en el encabezado foo.h , que se incluye dos veces: una vez desde foo.cpp y una vez desde main.cpp . Por lo tanto, cada unidad de traducción contiene su propia definición de foo . Tenga en cuenta que los guardias de foo.h en foo.h no evitan que esto suceda, ya que tanto foo.cpp como main.cpp incluyen foo.h separado . El resultado más probable de intentar construir este programa es un error de tiempo de enlace que identifica a foo como si se hubiera definido de forma múltiple.

Para evitar tales errores, se deben declarar funciones en los encabezados y definirlas en los archivos .cpp correspondientes, con algunas excepciones (ver otros ejemplos).

Funciones en linea

Una función declarada en inline se puede definir en múltiples unidades de traducción, siempre que todas las definiciones sean idénticas. También debe definirse en cada unidad de traducción en la que se utiliza. Por lo tanto, las funciones en línea deben definirse en los encabezados y no es necesario mencionarlas en el archivo de implementación.

El programa se comportará como si hubiera una sola definición de la función.

foo.h :

#ifndef FOO_H
#define FOO_H
#include <iostream>
inline void foo() { std::cout << "foo"; }
void bar();
#endif

foo.cpp :

#include "foo.h"
void bar() {
    // more complicated definition
}

main.cpp :

#include "foo.h"
int main() {
    foo();
    bar();
}

En este ejemplo, la función más simple foo se define en línea en el archivo de encabezado, mientras que la bar funciones más complicada no está en línea y se define en el archivo de implementación. Las unidades de traducción foo.cpp y main.cpp contienen definiciones de foo , pero este programa está bien formado ya que foo está en línea.

Una función definida dentro de una definición de clase (que puede ser una función miembro o una función amiga) está implícitamente en línea. Por lo tanto, si una clase se define en un encabezado, las funciones miembro de la clase se pueden definir dentro de la definición de la clase, aunque las definiciones se pueden incluir en varias unidades de traducción:

// in foo.h
class Foo {
    void bar() { std::cout << "bar"; }
    void baz();
};

// in foo.cpp
void Foo::baz() {
   // definition
}

La función Foo::baz se define fuera de línea, por lo que no es una función en línea y no debe definirse en el encabezado.

Violación ODR a través de la resolución de sobrecarga

Incluso con tokens idénticos para funciones en línea, se puede violar la ODR si la búsqueda de nombres no se refiere a la misma entidad. consideremos la func en lo siguiente:

  • header.h

    void overloaded(int);
    inline void func() { overloaded('*'); }
    
  • foo.cpp

    #include "header.h"
    
    void foo()
    {
        func(); // `overloaded` refers to `void overloaded(int)`
    }
    
  • bar.cpp

    void overloaded(char); // can come from other include
    #include "header.h"
    
    void bar()
    {
        func(); // `overloaded` refers to `void overloaded(char)`
    }
    

Tenemos una violación de ODR ya que overloaded refiere a diferentes entidades dependiendo de la unidad de traducción.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow