ページ 11

namespace , extern , include について

Posted: 2013年2月13日(水) 02:40
by shinpei
Dxライブラリで使う画像を Image という名前空間にまとめるために次のように書きました。

Image.h

コード:

namespace Image{
	extern const int graphics;
}
Image.cpp

コード:

#include "Image.h"
#include "DxLib.h"

const int Image::graphics = LoadGraph("graphics.png");
こうすることで、 Image.h を include すれば Image::graphics にアクセスできるようになったのですが、 graphics の値が-1(読み込み失敗)になってしまいます。
名前空間に extern const int test を加え、 image.cpp で test = 5 とすると上手くいき、また WinMain 関数内で同じように graphics.png を読むのも上手くいきます。
const を外しても同じでした。

なぜ名前空間内では失敗するのですか?

Re: namespace , extern , include について

Posted: 2013年2月13日(水) 07:45
by beatle
graphics変数をグローバル領域で初期化しようとしていますね。
グローバル領域での初期化はmain関数の実行より先に行われるため、DxLib_Init関数の実行よりも先にLoadGraphが実行されてエラーになっていると思います。

Re: namespace , extern , include について

Posted: 2013年2月13日(水) 12:29
by shinpei
なるほど…
load(){ Image::graphics = LoadGraph("graphics.png"); Image::test = LoadGraph("test.png"); ... }
というものを作り、DxLib_Init関数の実行後に呼ぶと読み込めました。

graphics や test を const にするにはどうすればよいのですか?

Re: namespace , extern , include について

Posted: 2013年2月13日(水) 13:15
by h2so5
初期化タイミングを制御したい場合にconstは使えないので、関数を使用してアクセス制御をする方法があります。

コード:

namespace Image {
    // ロード
    extern void Load();

    // 読み取り専用
    extern int get_graphics();
    extern int get_test();
}

コード:

namespace Image {

    // 外部からのアクセスを禁止
    namespace {
        int graphics;
        int test;
    }
    
    void Load()
    {
        graphics = LoadGraph("graphics.png");
        test = LoadGraph("test.png");
    }
    
    int get_graphics()
    {
        return graphics;
    }
    
    int get_test()
    {
        return test;
    }
}

Re: namespace , extern , include について

Posted: 2013年2月13日(水) 13:56
by shinpei
やはり const にするのは初期化のタイミング的に無理ということですね
教えていただいたように関数の戻り値から得ることにします

ところで、それならこうしても良いですよね?

コード:

class Image{
privete:
	static int graphics;
	
public:
	int get_graphics(){
		return graphics;
	}
}
定数をまとめる時、クラスと名前空間のどちらを使うのが適切なのですか?

Re: namespace , extern , include について

Posted: 2013年2月13日(水) 15:03
by h2so5
クラスを名前空間のように使う場合、これでは不十分です。
shinpei さんが書きました:

コード:

class Image{
privete:
	static int graphics;
	
public:
	int get_graphics(){
		return graphics;
	}
}
インスタンス生成を禁止するためにコンストラクタをprivateにしていますが、名前空間を使う場合よりも少し冗長になります。
機能的にはクラスを使っても名前空間を使っても同じです。

コード:

class Image{
private:
    Image();

private:
	static int graphics;
	
public:
	static int get_graphics(){
		return graphics;
	}
}
ただ、画像データのロードや参照などの機能をこのようなモノステートパターンで実装するのは良い設計とは思えません。
DXライブラリの関数は実行出来るタイミングが限定されているので、グローバルスコープからどのタイミングでもアクセスできる設計になっているとバグの原因になると思います。

Re: namespace , extern , include について

Posted: 2013年2月14日(木) 15:17
by shinpei
ありがとうございました