VC++

2010年2月13日 (土)

ヘッダーファイルに全部書く

今回、ファクトリーメソッドなぞをやろうと考えていたのですが、ちょっと横道に逸れます。

たとえば、下記のようなクラスを作ります。

class interface {
public:
    virtual void proc( void ) = 0;
public:
    static void set( interface* _obj ) {
        end();
        m_Current = _obj;
    }
    static void call( void ) {
        if( m_Current != NULL ) {
            return m_Current->proc();
        }
    }
    static void end( void ) {
        if( m_Current != NULL ) {
            delete m_Current;
            m_Current = NULL;
        }
    }
private:
    static interface* m_Current;
}
interface* interface::m_Current = NULL;

上記のコードをすべてヘッダーファイルに記述した状態でなんらかのプロジェクトに組み込み、ビルドします。が、これ通りません。

あちこちのソースファイルからこのファイルをインクルードすると、『m_Current』の実体がたくさんできてしまうためです。

それでは、どうすればいいのか・・・。『interface* interface::m_Current』の部分を一回だけ通すようにすればよいのです。とりあえず、キーワードを決めて、#ifdef~#endifを使用すればできなくはないですが、 ソースファイル側でキーワードを管理してやらなければならないので、いささか煩わしいです。

また、正攻法で『interface* interface::m_Current』の部分だけをソースファイルに記述してあげればいいのですが、このためだけにソースファイルを作るのもちょっと面倒くさいですね。

ということで、ちょっと調べたところ、『__declspec( selectany )』という素敵ワードを見つけました。まぁ、VC++限定なのですが。

MSDNの説明文には『At link time, if multiple definitions of a COMDAT are seen, the linker picks one and discards the rest.』と書かれています。これは、リンク時に複数できた実体を一つだけ残して、他を全部削除してくれるというものです。

この素敵ワードを『interface* interface::m_Current』に追加して、『__declspec( selectany ) interface* interface::m_Current = NULL』と記述してあげれば、めでたくビルドを通すことができます。

これで、題記の通り、ヘッダーファイルに全部書くことができました。

次回、話を元に戻して、ファクトリーメソッドです。

| | コメント (0) | トラックバック (0)