1

C 例

bb.c:

#include "bb.h"
#include <stdio.h>

void bb() {
    printf("aa()...\n");
    aa();
}

main.c:

#include "aa.h"
#include "bb.h"

int main(int argc, const char** argv) {

    aa();
    bb();

    return 0;
}

ああ:

#ifndef aa_h
#define aa_h

#include <stdio.h>

void aa() {
    printf("aa()...\n");
}

#endif // aa_h

bb.h:

#ifndef bb_h
#define bb_h

#include "aa.h"

void bb();

#endif // bb_h

C 結果

clang main.c bb.c でコンパイル:

duplicate symbol _aa in:
    /var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/main-OsFJVB.o
    /var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/bb-OkcMzn.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

C++ の例

b.cpp:

#include "b.hpp"

void b::do_something_else() {
    std::cout << "b::do_something_else() being called..." << std::endl;
    a a;
    a.doit();
}

main.cpp:

#include "a.hpp"
#include "b.hpp"

int main() {

    a a;
    b b;

    a.doit();
    b.do_something_else();

    return 0;
}

a.hpp:

#ifndef a_hpp
#define a_hpp

#include <iostream>

class a{
public:

    void doit() {
        std::cout << "a::doit() being called..." << std::endl;
    }

};

#endif // a_hpp

b.hpp:

#ifndef b_hpp
#define b_hpp

#include "a.hpp"

#include <iostream>

class b{
public:

    void do_something_else();

};

#endif // b_hpp

C++ の結果

上記は問題なくコンパイルclang++ main.cpp b.cppされ、プログラムへの出力は次のとおりです。

a::doit() being called...
b::do_something_else() being called...
a::doit() being called...

質問

  1. C++版で重複エラーが発生しないのはなぜですか?

  2. 関数void a::doit()がソース ファイルではなくヘッダー ファイルで定義されているということは、コンパイラが関数を自動的にインライン化するということですか?

4

3 に答える 3

2

C++ では、クラス メソッドは最上位のシンボルではありませんが、クラス階層内で効果的にスコープ指定された名前です。

doit()これは、C++ で 2 つのメソッドa::doit()を定義したことを意味します。b::doit()

aa()C では、1 つの関数を 2 回定義しようとしました。

同じクラスのスコープ内でdoit()メソッドを 2 回定義すると、C++ でもエラーが発生することに注意してください。

#include <iostream>

class a {

  public:

  void doit() {
    std::cout << "hello" << std::endl;
  }

  void doit() {
    std::cout << "goodbye" << std::endl;
  }
};

につながる

ed.cpp:11:8: error: ‘void a::doit()’ cannot be overloaded
   void doit() {
        ^
ed.cpp:7:8: error: with ‘void a::doit()’
   void doit() {
        ^
于 2014-07-09T03:46:39.000 に答える
1

あなたのC例でaaは、「1つの定義ルール」に違反する2回定義されています。である場合、これは同様に当てはまりますC++

あなたのC++例でa::doitは、 は 2 回定義されていますが、暗黙的に宣言されていinlineます。クラス内で定義されたメンバー関数は、次のように暗黙的にインライン化されます[dcl.fct.spec]/3

クラス定義内で定義された関数はインライン関数です。...

inline関数は、 ごとに 1 つの定義規則の例外です (実際、これがinline標準で要求される唯一の意味です) [basic.def.odr]/5

各定義が異なる翻訳単位に現れ、定義が次の要件を満たしている場合、外部リンケージ (7.1.2) を持つ ... インライン関数 ... の複数の定義がプログラムに存在する可能性があります。...

要件は本質的に、定義が表示されるすべての翻訳単位で定義が同一であるという要件に要約されます。

aaとして宣言したinline場合、同様のルールが適用され、コードはコンパイルされ、期待どおりに動作します。

于 2014-07-09T05:04:17.503 に答える
0

C++版で重複エラーが発生しないのはなぜですか?

重複がないからです。C++ メンバー関数は、それらが定義されているクラスによってスコープされます。b::doit() は、a::doit() の複製ではありません。

関数 void a::doit() がソース ファイルではなくヘッダー ファイルで定義されているという事実は、コンパイラが関数を自動的にインライン化することを意味しますか?

いいえ、可能です。

于 2014-07-09T03:46:46.077 に答える