none
C++/CLRにVC60のヘッダーファイルを定義すると”構造体の再定義”となります。 RRS feed

  • 質問

  • 1.C++/CLRの2つのフォームのヘッダーファイルにVC6.0の自分で作ったヘッダーファイルを
      定義すると”構造体の再定義”とります。そういうものなのですか?

    2.#pragma once の下に定義しています。
      一回だけしか読まないようになっているので大丈夫と思えるのですか?

    3."stdio.h"や"Windows.h"を2箇所の同じ場所に定義していますが、
      エラーは起こりませんが、その違いはなんなんでしょうか?

    4.stdafx.hに1箇所だけ定義すると、上手く行くのですが、
      stdafx.hは”参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイルを記述します。”
      となっています。  
      頻繁に変えるヘッダーファイルなので、良くないと思われますが?。
      (C++/CLRである程度動きだしたら、あまり変える必要がなくなるかもしれませんが)


    回避方法やヘッダーファイルの考え方なり教えて頂けたらと思います。

     

    2009年5月7日 2:27

回答

  • 1.C++/CLRの2つのフォームのヘッダーファイルにVC6.0の自分で作ったヘッダーファイルを
      定義すると”構造体の再定義”とります。そういうものなのですか?

    2.#pragma once の下に定義しています。
      一回だけしか読まないようになっているので大丈夫と思えるのですか?

    #pragma once をどこに記述していますか?
    #pragma once とは、「その記述があるヘッダーファイルを一度しかインクルードさせない」というものになります。今回のケースですと、VC6.0の自分で作ったヘッダーファイルの中に記述する必要があります。

    3."stdio.h"や"Windows.h"を2箇所の同じ場所に定義していますが、
      エラーは起こりませんが、その違いはなんなんでしょうか?

    一般的な二重インクルード防止のテクニックが使用されています。以下、stdio.h からの抜粋。
    #if     _MSC_VER > 1000
    #pragma once
    #endif
    
    #ifndef _INC_STDIO
    #define _INC_STDIO
    
        /***** この部分に定義内容 *****/
    
    #endif  /* _INC_STDIO */
    

    • 回答としてマーク クサキ 2009年5月11日 7:03
    2009年5月7日 6:32
  • CppClassLib_Global.h の中で関数の実体を定義していますよね?
    で、このヘッダー ファイルを cfAmenu.h と cfContorol_Hasei.h のそれぞれからインクルードしている、と。

    もしかして、この2つのヘッダー ファイルはそれぞれ cfAmenu.cpp と cfContorol_Hasei.cpp からインクルードされてはいませんか?
    もしそうであれば、それぞれのオブジェクトに実体が定義されてしまい、リンク時に二重定義になってしまいます。

    二重定義を回避するには、ヘッダー ファイル内の関数をインライン関数にしてしまうか、ヘッダー ファイルの中には関数のプロトタイプを宣言しておいて、関数の実体は別の cpp ソースに定義してリンクするといった方法があります。どちらを選択するかは関数の特徴に応じてということになりますが、今回は後者の方がいいように思います。
    • 回答としてマーク クサキ 2009年5月11日 7:04
    2009年5月8日 2:04

すべての返信

  • 1.C++/CLRの2つのフォームのヘッダーファイルにVC6.0の自分で作ったヘッダーファイルを
      定義すると”構造体の再定義”とります。そういうものなのですか?

    2.#pragma once の下に定義しています。
      一回だけしか読まないようになっているので大丈夫と思えるのですか?

    #pragma once をどこに記述していますか?
    #pragma once とは、「その記述があるヘッダーファイルを一度しかインクルードさせない」というものになります。今回のケースですと、VC6.0の自分で作ったヘッダーファイルの中に記述する必要があります。

    3."stdio.h"や"Windows.h"を2箇所の同じ場所に定義していますが、
      エラーは起こりませんが、その違いはなんなんでしょうか?

    一般的な二重インクルード防止のテクニックが使用されています。以下、stdio.h からの抜粋。
    #if     _MSC_VER > 1000
    #pragma once
    #endif
    
    #ifndef _INC_STDIO
    #define _INC_STDIO
    
        /***** この部分に定義内容 *****/
    
    #endif  /* _INC_STDIO */
    

    • 回答としてマーク クサキ 2009年5月11日 7:03
    2009年5月7日 6:32
  • 1.C++/CLRの2つのフォームのヘッダーファイルにVC6.0の自分で作ったヘッダーファイルを
      定義すると”構造体の再定義”とります。そういうものなのですか?
    そんなことはありません。
    正しく書いていれば特に困ることはなかったと思います。


    2.#pragma once の下に定義しています。
      一回だけしか読まないようになっているので大丈夫と思えるのですか?
    #pragma onceはどこに書いているのですか?
    構造体が定義されているヘッダに書いているのですか?

    回避方法やヘッダーファイルの考え方なり教えて頂けたらと思います。
    #pragma onceを使っていれば、大抵は問題ないとは思います。
    再現させるための簡単な例か、差し支えない範囲でのソースを書いてみて下さい。

    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年5月7日 14:39
    モデレータ
  • VC6.0の自分で作ったヘッダーファイルの中に記述したらOKになりました。
    ありがとうございました。

    関連で質問させてください。
    C++/CLR内で、グローバルなヘッダーファイルを作成した時、今度はリンク時にエラーになります。

    -----------------------------
    // CppClassLib_Global.h : 関数が定義されているヘッダーファイル (別プロジェクトのクラスライブラリーで定義)
    #pragma once
    void GlobalFunc_InCppClassLib( int *Param )
    {
         *Param = 10;
    };

    -----------------------------
    // cfAmenu.h  : 利用側1のフォームのヘッダーファイル
    #pragma once
    #include "..\\CppClassLib\\CppClassLib_Global.h" 

    -----------------------------
    // cfContorol_Hasei.h : 利用側2のフォームのヘッダーファイル
    #pragma once
    #include "..\\CppClassLib\\CppClassLib_Global.h" 

    -----------------------------
    リンク時に、プロジェクトのメインの cppファイルのところで、
    CppMain.obj : error LNK2005: "void __cdecl GlobalFunc_InCppClassLib(int *)" (?GlobalFunc_InCppClassLib@@YAXPAH@Z) は既に cfControl_Hasei.obj で定義されています。


    -----------------------------
    利用側プロジェクトやコントロールの別のプロジェクトでも同様のことをしてもOKです。
    ただ、ヘッダーファイルと名前空間の位置の関係か良く分かりませんが、
    チョットしたことで2重定義のようなエラーが発生することがありますのでよろしくお願いします。



     

    2009年5月8日 1:48
  • CppClassLib_Global.h の中で関数の実体を定義していますよね?
    で、このヘッダー ファイルを cfAmenu.h と cfContorol_Hasei.h のそれぞれからインクルードしている、と。

    もしかして、この2つのヘッダー ファイルはそれぞれ cfAmenu.cpp と cfContorol_Hasei.cpp からインクルードされてはいませんか?
    もしそうであれば、それぞれのオブジェクトに実体が定義されてしまい、リンク時に二重定義になってしまいます。

    二重定義を回避するには、ヘッダー ファイル内の関数をインライン関数にしてしまうか、ヘッダー ファイルの中には関数のプロトタイプを宣言しておいて、関数の実体は別の cpp ソースに定義してリンクするといった方法があります。どちらを選択するかは関数の特徴に応じてということになりますが、今回は後者の方がいいように思います。
    • 回答としてマーク クサキ 2009年5月11日 7:04
    2009年5月8日 2:04
  • 二重定義になるといった問題は、C++/CLR固有の問題ではありません。
    C++でのテクニック全般について、色々と身につけていかないと、C++/CLRで組み上げるのは大変かも。
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年5月8日 15:31
    モデレータ
  • CppClassLib_Global.h の中で関数の実体を定義していました。
    同名の.cppファイルを作り、実体をそちらに移しVC6.0時と同じようにしたら起こらなくなりました。
    ありがとうございました。
    2009年5月11日 7:03