Zoeken…


Vermenigvuldig gedefinieerde functie

Het belangrijkste gevolg van de One Definition-regel is dat niet-inline functies met externe koppeling slechts eenmaal in een programma moeten worden gedefinieerd, hoewel ze meerdere keren kunnen worden verklaard. Daarom moeten dergelijke functies niet in kopteksten worden gedefinieerd, omdat een koptekst meerdere keren uit verschillende vertaaleenheden kan worden opgenomen.

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 dit programma is de functie foo gedefinieerd in de kop foo.h , die twee keer is opgenomen: eenmaal van foo.cpp en eenmaal van main.cpp . Elke vertaaleenheid heeft daarom zijn eigen definitie van foo . Merk op dat de include-bewakers in foo.h dit niet voorkomen, omdat foo.cpp en main.cpp beide afzonderlijk foo.h . Het meest waarschijnlijke resultaat van het proberen om dit programma te bouwen is een link-time fout die foo identificeert als meervoudig gedefinieerd.

Om dergelijke fouten te voorkomen, moet men functies in headers declareren en deze in de overeenkomstige .cpp bestanden definiëren , met enkele uitzonderingen (zie andere voorbeelden).

Inline functies

Een inline gedeclareerde functie kan in meerdere vertaaleenheden worden gedefinieerd, op voorwaarde dat alle definities identiek zijn. Het moet ook worden gedefinieerd in elke vertaaleenheid waarin het wordt gebruikt. Daarom moet inline functies worden gedefinieerd in headers en er is geen noodzaak om ze te vermelden in de uitvoering bestand.

Het programma zal zich gedragen alsof er een enkele definitie van de functie is.

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 dit voorbeeld is de eenvoudigere functie foo wordt inline gedefinieerd in het header-bestand terwijl de meer gecompliceerde functie bar is niet inline en wordt gedefinieerd in de uitvoering bestand. Zowel de vertalingseenheden foo.cpp als main.cpp bevatten definities van foo , maar dit programma is goed gevormd omdat foo inline is.

Een functie gedefinieerd binnen een klassedefinitie (die een ledenfunctie of een vriendenfunctie kan zijn) is impliciet inline. Als een klasse in een koptekst wordt gedefinieerd, kunnen daarom lidfuncties van de klasse worden gedefinieerd in de klassedefinitie, hoewel de definities kunnen worden opgenomen in meerdere vertaaleenheden:

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

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

De functie Foo::baz is out-of-line gedefinieerd, dus het is geen inline-functie en mag niet worden gedefinieerd in de koptekst.

ODR-overtreding via overbelastingsresolutie

Zelfs met identieke tokens voor inline-functies kan ODR worden geschonden als het opzoeken van namen niet naar dezelfde entiteit verwijst. laten we func overwegen in het volgende:

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

We hebben een ODR-overtreding, omdat overloaded verwijst naar verschillende entiteiten, afhankelijk van de vertaaleenheid.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow