「extern」の私の認識について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
KRNKRS

「extern」の私の認識について

#1

投稿記事 by KRNKRS » 6年前

こんにちは。

最近私はC++(+DXライブラリ)を使用したプログラムの勉強と練習として東方を真似たシューティングゲームを作っているのですが、
そんな中「extern」の存在を知りました。

そこで皆さんに伺いたいのですが、
現在私は、例えば「Player.cpp」にある自機構造体の「x」と「y」という自機座標の変数の値を、

コード:

void PlayerInB_Pos(float *X,float *Y){
	*X = Ch.x;
	*Y = Ch.y;
}
と、関数を使用して値を渡してやってます。

しかし、私がこの掲示板やWebで調べた限りでの「extern」の使用用途は、所謂C#での、

コード:

//Player.cs
//~省略~
public float Player_x;
public float Player_y;

Player_x = 100.0f;
Player_y = 100.0f;
//~省略~

コード:

//Bullet.cs
//~省略~
public float Bullet_x;
public float Bullet_y;

Bullet_x = Player.Player_x;
Bullet_y = Player.Player_y;
//~省略~
と、「Player.Player_x」のように他ファイルの変数の値を参照するものと同じようなものなんでしょうか?
ただ、「extern」を使用した場合はどうやら、「どっかのcppファイルにある『Player_x』という変数」のように、全てのファイル総探りで変数を見つけてその値を使うようなので、変数にはきちんと「どの変数なのか明らかな、また唯一の変数名」にしなければならないようですが。

そこで、コードを上記の「Player.cpp」での関数を使用したやり方でなく、「extern」を使用して書きなおしてみました。
ソースコードの動作意図は、「自機座標を、弾の座標変数に代入してやる」です。

コード:

//~省略~
//自機構造体
extern Ch_t Ch;

//~省略~

//弾構造体のそれぞれの座標変数に自機座標変数を代入
Bul[i].x = Ch.x;
Bul[i].y = Ch.y;
//~省略~
一応このコードで問題なく関数で渡してやってた時と同様の動作を行ったのですが、如何せんまだ「extern」についてまだ知識が浅いもので、
本当にこのような使い方で合っているのか皆さんに確認を頂きたいです。

よろしくお願いいたします。
長文失礼しました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 「extern」の私の認識について

#2

投稿記事 by softya(ソフト屋) » 6年前

C#でもpublicにするのはオブジェクト指向のカプセル化にとってアウトな行為ですが、C/C++のexternも似たようなものです。なのでなるべく避けて下さい。
あと、C++の文法で書かれていないんですか? 参照とか使われていない様ですが。

【補足】
extern はグローバルスコープな変数などを作るときに使います。
グローバルスコープはカプセル化と真逆の行為なので、注意が必要です。 [← 書き漏れ追加]
「よくわかるC言語 - 第4回 変数のスコープをアドレスを使って理解する:ITpro」
http://itpro.nikkeibp.co.jp/article/COL ... 23/251565/
「ロベールのC++教室 - 第68章 寿命 -」
http://www7b.biglobe.ne.jp/~robe/cpphtm ... 01068.html
「ロベールのC++教室 - 第69章 リンケージ -」
http://www7b.biglobe.ne.jp/~robe/cpphtm ... 01069.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

KRNKRS
記事: 40
登録日時: 6年前
連絡を取る:

Re: 「extern」の私の認識について

#3

投稿記事 by KRNKRS » 6年前

返信有難う御座います。

まだC++そのものを勉強し始めて一年も経っていないので色々と理解出来ていない文法があり、参照もその内の一つでした。

調べた所によると参照は「値渡し」と「参照渡し」があり、

●値渡し
 ・「元変数→渡される変数」の一方通行の動作を行うもの。
 ・「元変数の値」は「渡される変数の値」に干渉されない。
 ・ただ、「変数をコピーして渡す」ので、その分メモリを食うし若干遅い。

●参照渡し
 ・元変数を別の名前で扱えるようにするもの。
 ・値渡しのように「変数をコピーして渡す」ことがないので、大きなオブジェクト等を扱いやすい。
 ・コピーしないため速度が値渡しより早い。

以上の解釈でよろしいでしょうか?
参考にしたサイト様
http://homepage2.nifty.com/well/Reference.html

その上でお聞きしたいのですが、
例えば、「Player.cpp」に、

コード:

float x = 0;
float& rx = x;
と定義したとします。
この時、「rx」は「x」を参照する参照変数になると思うのですが、これを他のファイル、例えば「Bullet.cpp」で扱いましょうということでしょうか?
そういった場合、どのように扱えばよろしいのでしょうか。
色々と調べては見たのですが、どれも同じcppファイル内で扱っているものばかりでわかりませんでした。

私がこのトピックを立てた時に書いた、

コード:

void PlayerInB_Pos(float *X,float *Y){
    *X = Ch.x;
    *Y = Ch.y;
}
に似た形で、関数を用いて渡してやらないといけないんでしょうか?
私が見た限りのサイトでは、関数を経由させて値を渡しているように見えました。(違ったらすいません)
C#を初めに扱ってきた私としては、やはり関数経由で値を渡すという方法は少しばかり煩わしいものがあるのですが、やはりコレ以外の方法ではムリなのでしょうか(externを使わない場合で)。

と、ここまで書いていて思ったのですが、私はどうやら参照の使い道や使い方を全然理解出来ていないようだと感じました。
「ポインタに似た動作なのか?」程度。

こちらのサイト様
http://sealsoft.jp/ptr_and_ref.html
によると、
「ポインタと異なる点は、「一度初期化したあとはその指すアドレスを変更できない」という点である。」
ということから、参照はポインタのconstバージョンみたいなものでしょうか?
となるとやはり関数経由?? (;´-ω-)ンーーー……混乱してきたぞ……。

とまぁコレ以上書くと異常に長くなりそうなのでまとめます。

①「extern」や関数を使用せずに他ファイルの変数の値を得ることは可能か?
②参照はポインタのconstバージョン?
③参照を用いて関数を使用せずに他ファイルの変数の値を得ることは可能か?

一つのトピックに複数の質問を投げかけるのは失礼だと思ったのですが、どれも「他ファイルの値を得たい」という希望に関連するものだったのでまとめさせて頂きました。申し訳ありません。

どうかよろしくお願いいたします。
最後に編集したユーザー KRNKRS on 2013年7月27日(土) 02:22 [ 編集 3 回目 ]

KRNKRS
記事: 40
登録日時: 6年前
連絡を取る:

Re: 「extern」の私の認識について

#4

投稿記事 by KRNKRS » 6年前

あっ! だめじゃん!
「関連する」とかほざいておきながらこのトピック元々『「extern」の私の認識について』のトピックじゃん!

質問が変わってしまい申し訳ありません。

KORYUOH
記事: 44
登録日時: 7年前

Re: 「extern」の私の認識について

#5

投稿記事 by KORYUOH » 6年前

簡単に私の見解をまとめておきます

1.externを使用しないのであればクラスのメソッドが必要になります。
2.参照はポインタのconst版ではありません。参照は「ポインタのアドレスの中身」を参照しているので変更することができます。ただし、const int& などのようにすれば変更はできません

例 addは通るがadd2はエラーになるはず

コード:


void add(int& a,int b){

	a+=b;

}

void add2(const int& a,int b){

	a+=b; //エラー

}

int main(void){
	int x=10,y=5;

	std::cout<<x<<std::endl; //10

	add(x,y);

	std::cout<<x<<std::endl;//15

	return 0;
}

3.正しく構造化されていても関数(メソッド)を用いずに値を得ることはまず無理です。
C言語を使うと自分の足を誤って撃ち抜いてしまうことがある。 C++を使えばそのような間違いを犯しにくくなる。しかし、やってしまったときには足全体が無くなる。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 「extern」の私の認識について

#6

投稿記事 by softya(ソフト屋) » 6年前

> 一つのトピックに複数の質問を投げかけるのは失礼だと思ったのですが、どれも「他ファイルの値を得たい」という希望に関連するものだったのでまとめさせて頂きました。申し訳ありません。

externからは外れますが根本の問題の解決のためなので、このまま続けましょう。
こちらとしては、externやポインタによる参照渡し、C++の参照渡し以前にカプセル化を考えて頂く必要がありそうだと思っています。

ちなみに参照渡しはC#にもあります。refをつけると参照渡しです。
「参照渡し - C# 階梯」
http://www.wgag.net/csharp/0050.html

> C#を初めに扱ってきた私としては、やはり関数経由で値を渡すという方法は少しばかり煩わしいものがあるのですが、やはりコレ以外の方法ではムリなのでしょうか(externを使わない場合で)。

うーん。誤解というかC++とC#で同じなんですけどね。publicに極力するな。グローバルにするなです。
その考え方だとC#での組み方にも問題が有った事になります。

>と、ここまで書いていて思ったのですが、私はどうやら参照の使い道や使い方を全然理解出来ていないようだと感じました。
>「ポインタに似た動作なのか?」程度。

C#でも必要性を感じをおられなかった様なので、根っこの問題は同じかなと言う気がします。
安全なカプセル化のために必要な機能です。

①「extern」や関数を使用せずに他ファイルの変数の値を得ることは可能か?
classで参照する方法もありますが、それはC#での方法と同じで問題があります。
カプセル化に反しているとか、externと根本的に変わらないとか、classのインスタンス生成にデメリットが・・・。とか。

②参照はポインタのconstバージョン?
型・サイズ違いの無理やり参照やnullやポインタ演算を許さない安全なポインタといったところでしょうか。

③参照を用いて関数を使用せずに他ファイルの変数の値を得ることは可能か?
それはexternの方が素直です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: 「extern」の私の認識について

#7

投稿記事 by h2so5 » 6年前

C++で型が異なる参照を無理やり作ることは可能です。

コード:

std::string a;
int& b = reinterpret_cast<int&>(a);

KRNKRS
記事: 40
登録日時: 6年前
連絡を取る:

Re: 「extern」の私の認識について

#8

投稿記事 by KRNKRS » 6年前

返信が遅れて申し訳ありません。テスト期間の合間に返信させていただいています。
皆さんの返信を読む限り、そもそも別ファイルの値を得るということ自体がプログラムのカプセル化に反していてあまりよくないようですね。

>こちらとしては、externやポインタによる参照渡し、C++の参照渡し以前にカプセル化を考えて頂く必要がありそうだと思っています。

確かに、C#をやっていた(期間は1年ほど、大学に入って初めて触れたプログラム言語)頃でもカプセル化の意味がよく理解できておらず、
「んん? 値がprivateになっているだと(エラー表示)? じゃあpublicじゃあっ! っしゃあ! 使えるようになったぁ! 解決!」
と、何も考えずにpublicに書き換えていました。


>externを使用しないのであればクラスのメソッドが必要になります。
C++クラス(C#も同じかもしれませんが)というかそもそもクラスがどのようなものかまだよくわかっていないので勉強します。。。。
調べたところによると構造体のハイスペックバージョンだとか。
参考したサイト様
http://www.asahi-net.or.jp/~wv7y-kmr/me ... p_cls.html


以上もろもろの皆様の返信を読んで…………

「俺よくこれで動くプログラム書けてたな!?」と自分で自分に突っ込んでしまいました(汗)

とりあえずは、
・カプセル化を考えに入れた場合、他ファイルの値はなるべく得ないようにしたほうが良い。
・もしどうしても得たいのであれば、「const (参照変数)」を用いて関数経由で値を得、元々の値は変わらないようにする。

の受け取り方でよろしんでしょうか?
それで、もし、「const (参照変数)」を用いる場合、

コード:

//Player.cpp
void InPos(float& Bl_x,float& Bl_y){
        const float& x = (PlayerのX座標);
        const float& y = (PlayerのY座標);

        Bul_x = x;
        Bul_y = y;
}
と書くのが正しいんでしょうか?
今手元にプロジェクトファイルがなく、このコードの確認ができないので申し訳ないですが合否のほどよろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 「extern」の私の認識について

#9

投稿記事 by softya(ソフト屋) » 6年前

Bul_x = x;
Bul_y = y;
これだと元からコピーしているので、
const float& x = (PlayerのX座標);
const float& y = (PlayerのY座標);
自体が不要です。
コピーと参照が訳分からん状態になっているように感じますね。
構造体やクラスに値をコピーして構造体やクラスを戻り値で返せば変更される恐れはありませんので、そういう方法もあります。

> 調べたところによると構造体のハイスペックバージョンだとか。
それは実装の問題ですね。 オブジェクト指向の理念とまた別の問題です。
C++のクラスはオブジェクト指向を実践するために設計されていますが、それをオブジェクト指向の手段として使うのは使い手の知識と心がけが必要です。まぁ、これはC#でも同じですけどね。

【補足】
> ・カプセル化を考えに入れた場合、他ファイルの値はなるべく得ないようにしたほうが良い。

表面的に捉えずに、なぜカプセル化するのか、オブジェクトと呼ばれるのかを考えて下さい。
そうすれば、自ずとやるべきことが決まります。

> ・もしどうしても得たいのであれば、「const (参照変数)」を用いて関数経由で値を得、元々の値は変わらないようにする。

それも短絡的だと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

KRNKRS
記事: 40
登録日時: 6年前
連絡を取る:

Re: 「extern」の私の認識について

#10

投稿記事 by KRNKRS » 6年前

ようやくテスト期間が終わり返信させて頂きます。

>コピーと参照が訳分からん状態になっているように感じますね。
やはりまだ勉強不足のようです。出直してきますm(_ _)m

カプセル化についてもまだ私の認識があいまいな状態なのでサイトを見つつ、プログラムを初めから作り直しながらカプセル化について理解を深めて行きたいと思います。

今回のトピックの『「extern」の私の認識について』はおおよそ理解出来た(はず)ので、今回のこのトピックを解決とさせて頂きます。

今回のやり取りで新たに出た疑問などは、ちゃんと別のトピックにて改めて質問させて頂きます。

ここまで長い間付き合っていただいてありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る