11768


C++初心者です。複数のファイルを取り込んだプログラムがコンパイルできず、その理由もわかりません。

A.cpp

[code]

    #include "B.h"
    
    int main(int argc, char **argv) {
        B test;
        test.show(*argv);
        return 0;
    }
    
[/code]

B.h

[code]

    #pragma once
    
    #ifndef __B_H__
    #define __B_H__
    
    #include <string>
    
    class B {
    public:
        void show(std::string);
    };
    
    #endif
    
[/code]

B.cpp

[code]

    #include "B.h"
    
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    class B {
    public:
        void show(const char *var) {
            cout << var << endl;
        }
    };
    
[/code]

これでコンパイル

[code]

    g++ -o a.exe A.cpp
    
[/code]

すると

[code]

    /tmp/ccGn41oP.o:A.cpp:(.text+0x4c): `B::show(std::string)' に対する定義されていない参照です
    /tmp/ccGn41oP.o:A.cpp:(.text+0x4c): 再配置がオーバーフローしないように切り詰められました: R_X86_64_PC32 (未定義シンボル `B::show(std::string)' に対して)
    collect2: エラー: ld はステータス 1 で終了しました
    
[/code]

こうなってしまいます。  
これはどういうエラーなんでしょうか。  
こんな初歩的な質問で恐縮ですが、教えてください。

> ご回答について

ご回答ありがとうございます。  
コンパイルの流れを理解していませんでした。  
おっしゃる通り、

[code]

    g++ -c B.cpp
    
[/code]

を実行したところ、

[code]

    $ g++ -c B.cpp
    B.cpp:8:7: エラー: ‘class B’ が再定義されています
     class B {
           ^
    In file included from B.cpp:1:0:
    B.h:8:7: エラー: ‘class B’ の前の定義
     class B {
           ^
    
[/code]

となってしまったため、プロトタイプの実装本体はクラス宣言しないのかと思い、  
下記に変更して再度実行しました。

B.cpp

[code]

    #include "B.h"
    
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    void show(const char *var) {
        cout << var << endl;
    }
    
[/code]

これで"B.o"というファイルが生成され、改めて

[code]

    g++ -o A.exe A.cpp
    
[/code]

を実行したものの、エラーの内容が変わりませんでした。

> sayuri さん

ちなみにですが・・・  
引数を

[code]

    void show(std::string var);
    
[/code]

に統一し、

[code]

    g++ -c B.cpp
    g++ -o A.exe A.cpp
    
[/code]

を行うと

[code]

    $ g++ -o a.exe A.cpp
    /tmp/ccSVMoNA.o:A.cpp:(.text+0x4c): `B::show(std::string)' に対する定義されていない参照です
    /tmp/ccSVMoNA.o:A.cpp:(.text+0x4c): 再配置がオーバーフローしないように切り詰められました: R_X86_64_PC32 (未定義シンボル `B::show(std::string)' に対して)
    collect2: エラー: ld はステータス 1 で終了しました
    
[/code]

というエラーになります。

<http://d.hatena.ne.jp/pknight/20090826/1251303641>

このブログを見ると、この場合はtemplate関数の場合ですが、  
「この関数は使われていないから.objを生成しても実態がないのでA.cppからは実装が見えません」  
というようなことが書いてありました。  
もしこれと同様の現象が起きているのだとすると、今回show()関数はグローバルメンバ関数ではなくクラスメンバ関数なのでA.cppから見ることはできない  
ということになってしまうんでしょうか。  
言語仕様をほとんどよくわかっていないので、さすがにそんなことはないんじゃないかと思いますが・・・

C++開発者の方も、実行ファイル1つで完結するプログラムなんてそうそう書かないと思いますが、  
皆さんはどうやって外部関数を参照しているのかわかりません。


CC BY-SA 3.0
2015-06-26T05:13:20.657
11755
2017-07-25T06:21:09.100
2015-06-26T07:20:47.617
8396
8396
question
c++
C++で外部クラスを使用したプログラムがコンパイルできない


コンパイル、コンパイルといいますが、厳密には以下のフェーズに分かれています。  
(1)コンパイル：ソースコードからオブジェクトファイルを生成  
(2)リンク：オブジェクトファイルを紐づけて実行形式ファイルを生成

つまり、  
[A.cpp, B.cpp, B.h] --(1)--> [A.o, B.o] --(2)--> [A.exe]  
ということです。

で、上記のエラーメッセージを見る限りリンクのフェーズでエラーが発生しています。  
内容を見るとB::Showが、恐らくはB.obj見つかりません、という事ですね。  
(1)はソースコード単位で行われます。  
ですので、B.objが作成されていないのでは？、と見受けられます。。  
g++ -c B.cpp  
を実施すれば解決するかと。


CC BY-SA 3.0
2015-06-26T05:30:54.637
11757
2015-06-26T05:30:54.637
10256
11755
answer


C言語及びC++言語には宣言と定義の２つが存在します。  
B.hに

[code]

    class B {
    public:
        void show(std::string);
    };
    
[/code]

と宣言した場合、B.cppに記述すべきこれに対応する定義は

[code]

    void B::show(std::string){
        ...
    }
    
[/code]

となります。C言語と異なりC++言語には関数オーバーロードがあるため、引数を完全に一致させる必要があります。また `void
B::show(std::string)` と `void show(std::string)` も別関数です。


CC BY-SA 3.0
2015-06-26T06:46:38.657
11768
2015-06-26T06:46:38.657
4236
11755
answer


ソースファイルが複数に分かれている場合, ビルド手順は以下のいずれかの方法になります.

A. ソースファイルを個別にコンパイルし, 後でリンクする.

[code]

    g++ -c A.cpp
    g++ -c B.cpp
    g++ -o a.exe A.o B.o
    
[/code]

最初の2行で, それぞれ A.o と B.o を生成します. 「-c」オプションをつけた場合,
拡張子を.oに置き換えたものがデフォルトの出力ファイル名になります.  
3行目で, リンクします.  
規模が大きいとこの方法が主流です. 下の方法と比べて, ソースを一部変更した後の再コンパイル・ビルドがです.

B. まとめてコンパイル, リンクする.

[code]

    g++ -o a.exe A.cpp B.cpp
    
[/code]

1行でかけるので手軽ですが, 中間のオブジェクトファイルが残らないので, 一部を修正した場合でも両方のソースをコンパイルし直すことになり,
時間がかかります.

ソースコードにエラーがあり, sayuriさんの回答にもあるとおり, B.cppを以下のように修正する必要があります.

[code]

    #include "B.h"
    #include <string>
    #include <iostream>
    using namespace std;
    void B::show(std::string var) {
      cout << var << endl;
    }
    
[/code]


CC BY-SA 3.0
2017-07-25T06:21:09.100
36651
2017-07-25T06:21:09.100
68
11755
answer