ページ 11

C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 01:03
by stm
環境 visual studio2013 windows8.1
C++ 入門サイトやここのサイトを一通り勉強しました


一つのファイルに同じクラス定義や関数定義を二つ書くと
コンパイルの段階でエラーになります
では次の二つの場合の挙動の違いについて教えてください

test.h------------------------

コード:

void Test(){

printf("test");
}
---------------------------
a.cpp-------------------------

コード:

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

void Test1();

int main(){

Test1();

}
------------------------------
b.cpp--------------------------------

コード:

#include"testh.h"

void Test1(){

Test();
printf("test1");
}
------------------------------

↑はコンパイルは通りますがリンカの段階でTest()が二重定義とされエラーになります


test.h-----------------------------

コード:

class CTest{
public:
int a;
int b;

};
---------------------------
a.cpp-------------------------

コード:

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

void Test1(CTest& Test);

int main(){
CTest Test;
Test1(Test);
return 0;
}
------------------------------
b.cpp--------------------------------

コード:

#include"testh.h"

void Test1(CTest& Test){

Test.a = 5;
Test.b = 3;
}
------------------------------
↑問題なくコンパイルもリンクも通る


①はTest()の定義がa.objとb.objにそれぞれインクルードされたため同じ関数の定義がファイルをまたいで二つあるのでリンカエラーが起きたのだと思います
ならば②も同様にファイルをまたいでCTestのクラス定義がa.objとb.objにインクルードされているのでエラーが起きると思うのですが、起きません。

今ままでなんとなくファイル分割をしてきたので、この違いがわかりません。
どうかご教授ください

なるべく専門的な範囲(リンカの挙動の違いとか)でわかりやすく(無茶ですいません)おねがいします

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 01:11
by h2so5
クラス定義は重複していてもエラーにはなりません。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 08:15
by naohiro19
struct でも同じことが言えます。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 13:05
by stm
同じクラス定義を同じソースファイルに二つ書くとコンパイルエラーになりますが
同じクラス定義をファイルを跨いで二つ書いてもエラーになりません

この違いをコンパイラやリンカの挙動の観点から教えてください

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 13:16
by softya(ソフト屋)
用語の細かい所はおいておいて、コンパイラは1つのソースファイルとインクルードしているヘッダだけをみてオブジェクトファイルを生成します。なので1つのソースファイル内で検出できるエラーを検出します。
リンカはオブジェクトファイルを結合しますので、名前がオブジェクトファイル間で同じものが出てくる場合リンカでしかエラー判定しようがりません。
コンパイラとリンカの動作を考えれば推測できると思いますが。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 17:29
by stm

コード:

// Test1.cpp
class CTest
{
public:
    int a;
    int b;

    void Func();
};

void CTest::Func()
{
    b = 0;
}

CTest a;

コード:

// Test2.cpp
class CTest
{
public:
    int a;

    void Func();
};

CTest b;

int main()
{
    b.Func();
}
これをコンパイルリンクしてもエラーは出ないそうです((((;゚Д゚)))))))
関数で、同じ名前違う実装の関数を二つ定義したらエラーになるのに、クラス場合は許されちゃうんですね〜
クラス定義と関数定義の違いを勉強してきます

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 19:02
by ISLe()
【定義】には2種類あります。
1. 宣言のうち、実体の生成を伴うもの
2. 宣言以外で識別子を生成するもの

関数定義は1.で、クラス定義は2.です。

1.の定義が現れればコンパイル単位で実体が生成されます。

2.の定義は、コンパイル単位で、必要なときに既に定義されていなければコンパイルエラーになりますが、定義自体は実体を持ちません。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 19:40
by softya(ソフト屋)
話が飛びましたがコンパイルとリンクの違いは理解されたのでしょうか?

>これをコンパイルリンクしてもエラーは出ないそうです((((;゚Д゚)))))))
>関数で、同じ名前違う実装の関数を二つ定義したらエラーになるのに、クラス場合は許されちゃうんですね〜
>クラス定義と関数定義の違いを勉強してきます

関数のオーバーロードを調べて下さい。
調べると分かりますがC++の場合はクラスではない関数でもオーバーロード出来ます。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 21:47
by stm
おおお!ISLe()さんの情報が多分僕が一番知りたかったことです。クラス定義と関数定義の違いが明確になりました。「識別子」「関数の実体」の具体的専門的な説明が欲しいのですが、参考になるサイト文献があれば教えてください。

ソフト屋さん
関数のオーバロードは引数の種類個数=シグネチャが違わなければ作用せず、おなじ関数名、シグネチャの関数定義がファイルを跨いで存在すると、ファイル単位で行われるobjファイル生成コンパイルは正常に行われるが、それらをつなげる(コンパイル時に未設定だった、他ファイルにある関数へのアドレスを設定する?)リンカの段階で、同じ関数名を区別できないので、リンクエラーになる

私の理解はこんな感じです

ここで私は、「区別できない関数定義をファイル跨ぎで二つ書くとダメだよなー。え?でもクラス定義は分割したファイルそれぞれにインクルードしてきたじゃん。なんで関数の時のようにエラーでないの?」と思ったわけです。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 21:57
by h2so5
stm さんが書きました:おおお!ISLe()さんの情報が多分僕が一番知りたかったことです。クラス定義と関数定義の違いが明確になりました。「識別子」「関数の実体」の具体的専門的な説明が欲しいのですが、参考になるサイト文献があれば教えてください。
C++の規格書を読みましょう。
識別子については"3.5 Program and linkage" , 関数の実体については、"3.1 Declarations and definitions" に書かれています。
http://www.open-std.org/jtc1/sc22/wg21/ ... /n3690.pdf

Re: C++ ファイル分割と重複定義

Posted: 2014年7月01日(火) 23:02
by stm
ありがとうございます!!(ひえー英語だー)
最後に質問なんですが、プログラマとして働くならば、触ったことのない言語はこのように外国語の規格書をよむのが常識なのでしょうか、それとも普通は分かりやすい入門書やサイトを利用して勉強し、深く知る必要があるときに規格書を漁るものなのでしょうか?

Re: C++ ファイル分割と重複定義

Posted: 2014年7月02日(水) 00:00
by ISLe()
JISC 日本工業標準調査会のJIS検索で日本語の規格書を読めます。
C言語はJISX3010、C++言語はJISX3014です。

日本語の訳は間違っていることがけっこうあるので注意してください。
ネットで検索すればJISの何が間違っているという情報も見付けることができますが。

Re: C++ ファイル分割と重複定義

Posted: 2014年7月02日(水) 10:30
by stm
答えてくださったみなさん、ありがとうございます。