VC++2008を使っています
まだ、C++を学び始めて間もないので、初歩的な質問なんですが…
比較的大きなプログラムだとソースコードを複数のファイルに分割して書きますよね…
その際に
例えばA .cpp とB.cppを作ったとして…
両方のファイルで同じ変数を扱うのには、どのような方法があるのでしょうか…
よろしくお願いいたします
ファイル分割の仕方
Re: ファイル分割の仕方
型Aのオブジェクトaを複数の翻訳単位からアクセスするには、どれかひとつの翻訳単位でaを定義し、他ではexternを付けて宣言します。
ただし、型Aに明示的なコンストラクタがある場合、あるいは定数式以外の初期化子を持つ場合は初期化の順序が問題になります。
これを回避するには、たとえば次のようにヘッダファイルでインライン関数を定義しておくと便利です。
これで、関数aを呼び出すことで、関数内で定義されている型Aのオブジェクトaにアクセスでき、しかも初期化順序の問題もクリアできます。
なお、デストラクタによる解体の順序まではコントロールできませんので、終了時処理の順序に依存する場合はさらに工夫が必要になります(高難度です)。
これを回避するには、たとえば次のようにヘッダファイルでインライン関数を定義しておくと便利です。
// A.hpp
#ifndef A_HPP_
#define A_HPP_
inline A& a()
{
static A instance;
return instance;
}
#endif
なお、デストラクタによる解体の順序まではコントロールできませんので、終了時処理の順序に依存する場合はさらに工夫が必要になります(高難度です)。
Re: ファイル分割の仕方
以下のような、グローバル変数を使うプログラムを例として考えます。
【A.cpp】
reset()という関数を別のファイル(B.cpp)に定義したいとしましょう。
【B.cpp】
外部で定義されている変数を使用するには、externというキーワードをつけて変数を宣言します。
また、このときのA.cppは以下のようになります。
【A.cpp】
ちなみに、
void reset();
という宣言は、
extern void reset();
を省略したもので、reset();という外部関数を使うという宣言になります。
【A.cpp】
#include <iostream>
// みんなで共有する変数
int shared;
// sharedの値をリセットする関数
void reset()
{
shared = 9999;
}
int main()
{
reset();
std::cout << shared << std::endl;
shared = 100;
std::cout << shared << std::endl;
reset();
std::cout << shared << std::endl;
}
【B.cpp】
// sharedの値をリセットする関数
void reset()
{
extern int shared; // sharedという外部変数を使用するという宣言
shared = 9999;
}
また、このときのA.cppは以下のようになります。
【A.cpp】
#include <iostream>
// みんなで共有する変数
int shared;
// C++では宣言されていない関数は使えないので、宣言が必要
// 通常これらの宣言は、ヘッダファイルとしてまとめて提供する
void reset();
int main()
{
reset();
std::cout << shared << std::endl;
shared = 100;
std::cout << shared << std::endl;
reset();
std::cout << shared << std::endl;
}
void reset();
という宣言は、
extern void reset();
を省略したもので、reset();という外部関数を使うという宣言になります。
-
MASSA
Re: ファイル分割の仕方
なるほど!
お二方、ありがとうございます。
ところで、extern宣言を使うと、その変数を検索する処理が入るんですよね?
処理速度への影響はどの程度あるのでしょうか…
お二方、ありがとうございます。
ところで、extern宣言を使うと、その変数を検索する処理が入るんですよね?
処理速度への影響はどの程度あるのでしょうか…
Re: ファイル分割の仕方
外部宣言の最終的な解決は,リンカの仕事になります。MASSA さんが書きました:ところで、extern宣言を使うと、その変数を検索する処理が入るんですよね?
処理速度への影響はどの程度あるのでしょうか…
なので,リンクの速度への影響はありますが,実行速度への影響はありません。
ただし,物理的なメモリ配置によるキャッシュへの影響から来る実行速度への影響は除きます。
# 同一翻訳単位の定義の方が物理的にまとまって配置されることが多い。
Re: ファイル分割の仕方
オブジェクトを直接参照する場合は影響ありません。MASSA さんが書きました:ところで、extern宣言を使うと、その変数を検索する処理が入るんですよね?
処理速度への影響はどの程度あるのでしょうか…
ただし、私が示した後者の方法(関数を介してアクセスする方法)の場合、若干のオーバーヘッドがあります。
オブジェクトの型によっては後者の方法を使うしかないので、まずはどんな型なのかを明らかにしてください。