Ricerca…


Funzione definita in modo multiplo

La conseguenza più importante della One Definition Rule è che le funzioni non inline con link esterno dovrebbero essere definite solo una volta in un programma, sebbene possano essere dichiarate più volte. Pertanto, tali funzioni non dovrebbero essere definite nelle intestazioni, poiché un'intestazione può essere inclusa più volte da diverse unità di traduzione.

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();
}

In questo programma, la funzione foo è definita nell'intestazione foo.h , che è inclusa due volte: una volta da foo.cpp e una volta da main.cpp . Ogni unità di traduzione contiene quindi la propria definizione di foo . Si noti che le guardie di foo.h in foo.h non impediscono che ciò accada, dal momento che foo.cpp e main.cpp entrambi includono separatamente foo.h Il risultato più probabile del tentativo di creare questo programma è un errore link-time che identifica foo come se fosse stato definito in modo multiplo.

Per evitare tali errori, è necessario dichiarare le funzioni nelle intestazioni e definirle nei corrispondenti file .cpp , con alcune eccezioni (vedere altri esempi).

Funzioni inline

Una funzione dichiarata in inline può essere definita in più unità di traduzione, a condizione che tutte le definizioni siano identiche. Deve anche essere definito in ogni unità di traduzione in cui viene utilizzato. Pertanto, le funzioni inline dovrebbero essere definite nelle intestazioni e non è necessario menzionarle nel file di implementazione.

Il programma si comporterà come se ci fosse una singola definizione della funzione.

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();
}

In questo esempio, la funzione più semplice foo è definita in linea nel file di intestazione mentre la bar funzione più complessa non è in linea ed è definita nel file di implementazione. Entrambe le unità di traduzione foo.cpp e main.cpp contengono le definizioni di foo , ma questo programma è ben formato poiché foo è in linea.

Una funzione definita all'interno di una definizione di classe (che può essere una funzione membro o una funzione amico) è implicitamente in linea. Pertanto, se una classe è definita in un'intestazione, le funzioni membro della classe possono essere definite all'interno della definizione della classe, anche se le definizioni possono essere incluse in più unità di traduzione:

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

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

La funzione Foo::baz è definito fuori linea, quindi non è una funzione inline, e non deve essere definito nell'intestazione.

Violazione di ODR tramite risoluzione di sovraccarico

Anche con token identici per funzioni inline, l'ODR può essere violato se la ricerca di nomi non si riferisce alla stessa entità. consideriamo func in following:

  • 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)`
    }
    

Abbiamo una violazione ODR come overloaded riferisce a entità diverse a seconda dell'unità di traduzione.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow