サーチ…


乗算された関数を定義する

1つの定義ルールの最も重要な結果は、外部リンケージを持つ非インライン関数は、複数回宣言することはできますが、プログラム内で1回のみ定義することです。したがって、異なる翻訳単位から複数のヘッダを含めることができるため、このような関数をヘッダに定義するべきではありません。

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

このプログラムでは、関数fooはヘッダーfoo.h定義されていますfoo.hfoo.cppから1回、 main.cppから2回main.cppます。したがって、各翻訳単位には独自のfooの定義が含まれています。 foo.hのインクルードガードは、 foo.cppmain.cpp両方にfoo.h 別々main.cppれているので、これを防ぐものではないことに注意してください。このプログラムをビルドしようとすると、 fooが複数定義されていると特定するリンク時エラーが発生する可能性が最も高いです。

このようなエラーを回避するには、ヘッダーに関数を宣言し、対応する.cppファイルで定義する必要があります(他の例を参照)。

インライン関数

inline宣言された関数は、すべての定義が同一であれば、複数の翻訳単位で定義することができます。また、それが使用されているすべての翻訳単位で定義する必要があります。したがって、インライン関数ヘッダーに定義する必要があり、実装ファイルに記述する必要はありません。

プログラムは、関数の単一の定義があるかのように動作します。

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

この例では、より単純な関数fooはヘッダーファイルでインラインで定義され、より複雑な関数barはインラインではなく、実装ファイルで定義されています。 foo.cppmain.cpp両方の翻訳単位にはfoo定義が含まれていますが、このプログラムはfooがインラインであるため適切な形式です。

クラス定義内で定義された関数(メンバ関数またはフレンド関数かもしれない)は暗黙的にインラインです。したがって、クラスがヘッダに定義されている場合、定義が複数の翻訳単位に含まれていても、そのクラスのメンバ関数をクラス定義内に定義することができます。

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

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

関数Foo::bazは行外で定義されているため 、インライン関数ではないので、ヘッダに定義してはいけません。

オーバーロード解決によるODR違反

インライン関数のトークンが同じであっても、名前の参照が同じエンティティを参照していない場合、ODRに違反する可能性があります。次のようにfuncを考えてみましょう:

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

overloadedれたODR違反は、翻訳単位に応じて異なるエンティティを参照しています。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow