none
VC++でクラスの生成ができません RRS feed

  • 質問

  • 環境:Visual C++ (Visual Studio2015);
       共通言語ランタイムサポート:Common Language Runtime Support (/clr)

    グラフィックに関するあるDLLを参照して、そのDLL内で定義されているクラス(AA::BB::CCとします)を生成しようとしています。

    これがコンパイルエラーでうまくいかず、原因も対処もよくわからないため困っています。
    C++の経験が乏しいため初歩的な問題かもしれませんが、アドバイスを頂きたいです。

    もともとは、当該のDLLを使ってVB .netで実装されていたアプリを、今回VC++に移行しようとしているものです。
    (当該のDLLは秘密保持のため、申し訳ありませんが具体的にはお伝えすることができません。)

    まず移行元のVB .netの実装ソースは下記の通りになっており、問題無く動作しています。

    =================================================
     Private Sub fff(ByVal g As Graphics)
       ・・・
       Dim foo As AA.BB.II = Nothing
       foo = New AA::BB::CC(g)
       ・・・
     End Sub
    =================================================

     ※クラスAA::BB::CCは、インターフェイスクラスAA::BB::IIの派生クラスです。
     ※クラスAA::BB::CCのコンストラクタはSystem::Drawing::Graphicsを引数としています。


    上記のVB .netのコードをVC++に移行したく、以下のように記述してみたのですが、これがコンパイルエラーとなってしまい困っています。

    =================================================
     System::Windows::Forms::PictureBox^ pic;
     ・・・
     Graphics^ g = pic->CreateGraphics(); //実際はオリジナルコードと同じくgは引数取得します
     AA::BB::II^ foo = gcnew AA::BB::CC(g);
     
     エラー C2365 'AA:BB::CC::0': 再定義; 以前の定義は 'プロパティ' でした。
    =================================================

    C2365の意味を確認し、概して名前のかぶる変数や関数を定義しようとした時のエラーであることは
    理解できるのですが、上記のクラス生成・参照変数への代入の場面でこのエラーとなる意味が
    どうしても分からず、対処できずにいます。
    (エラーメッセージ中、「::0」の部分が何を表しているかも不明です)

    なお、関係ないかもしれませんが、3行目でfooへの代入を行わず
      AA::BB::CC(^g); // gcnew宣言がないので「^」が必要?
    とだけした場合にはコンパイルは通ります。
    (インスタンスとして参照変数に代入できない以上 後続で使えず無意味ですが)

    また、コンストラクタ引数の渡し方の問題かなと思い、値渡しを試みる意味で下記を
    試してみましたがやはり同様のエラー(C2365)となりました。

    ==================================================
     Graphics ^%g = pic->CreateGraphics();
     AA::BB::II^ foo = gcnew AA::BB::CC(g);
     
     エラー C2365 'AA:BB::CC::0': 再定義; 以前の定義は 'プロパティ' でした。
    =================================================

    上記について何かお分かりの方がいらっしゃいましたら、是非ヒント、アドバイスお願いいたします。

    2017年6月16日 6:51

すべての返信

  • グラフィックに関するあるDLLを参照して、そのDLL内で定義されているクラス(AA::BB::CCとします)を生成しようとしています。
    名前が伏せられているのでわかりませんが、マクロと競合している可能性はありませんか?
    2017年6月16日 7:28
  • さっそくのコメント、どうもありがとうございます。

    頂いたコメントの回答になっているか自信がないのですが、下記の様に考えています。

    現在のプロジェクト内では、マクロ定義は特に行っていないので、何かと重複していることは考えにくいと思っています。

    このプロジェクトは画面アプリとして作っており、プロジェクト内のソースの構成としては
     ・画面フォームのヘッダファイル1本の中(namespace内)にロジックを全て記述
     ・cppからはフォームの gcnew とその ShowDialog()呼出 のみを行なう
    という構成で、当該のDLLは参照設定から取り込んでいます。

    画面フォーム ヘッダファイルの namespace宣言より前の部分では、以下の宣言3行のみです。
     #pragma once
     #include "Windows.h"
     #include "(当該DLL名).h"

    調べ方や情報が不足しているようでしたら、大変恐縮ですがご指摘いただければと存じます。

    2017年6月16日 9:33
  • 追伸です。

    試しにヘッダの冒頭3行目

     #include "(当該DLL名).h"

    を削除しても、問題の個所以外はコンパイルできることが分かりましたので、上記のincludeは余計だったかもしれません。

    それでもやはり、

     AA::BB::II^ foo = gcnew AA::BB::CC(g);

    の行に対しては変わらずエラー C2365 となります。

    2017年6月16日 9:45
  • 質問者です。 追記します。

    代入先の変数名 foo が予期しないところで重複している可能性を考えて、

     AA::BB::II^ foofoofoo = gcnew AA::BB::CC(g);

    としてみましたが、やはり変わらずエラー C2365 となります。

    原因が分からないため手詰まりに近い状態になってしまっているのですが、

    エラー C2365 が発生してしまう原因を探すために、何か試すべきアプローチはありますでしょうか。

    2017年6月16日 11:23
  • あくまで問題となっている名称は明かせず、調査方法を知りたいということでしょうか?

    そうであればコンパイルオプション /P が調査に使えるかと思います。

    • 回答の候補に設定 佐祐理 2017年6月16日 23:43
    2017年6月16日 12:43
  • エラーの本質については佐祐理さんが言われているとおり、/p でプリプロセスを通した結果のファイルを確認して、何が起きているかを調べた方が良いでしょう。
    (マクロ展開を回避したいとかなら、#undef あたりになるかもしれませんが)

    -----

    ところで、なぜ、VB.NET から C++/CLI かつ、Windows Forms の世界に移植されようとしているのでしょうか。
    C++/CLI における Windows Forms は Visual Studio 2012 から非推奨です。
    また、C++/CLI は C++ の知識・経験と、.NET の知識・経験の双方を求め、難易度がかなり高く、C++ とは異なる言語となります。
    C++ の知識がない中、C++/CLI と Windows Forms という先行きのない道を選ばれているという点が気にかかります…。
    (この先どうなるかわからない言語&テクノロジーの組み合わせを、苦労して作り上げて、次のバージョンで見捨てられたら悲しいことになるので、再考の可能性はないのかな?という視点からです。すでに C++/CLI & Windows Forms の置かれた状況や難易度について理解していて、なおかつ見直せない状況にあるのであれば、読み捨ててください)


    2017年6月16日 14:06
    モデレータ
  • 佐祐理さん, Azuleanさん

    アドバイスどうもありがとうございます。

    プリプロセスの確認でコンパイルオプション /Pというものがあるのですね。
    現在、手元に環境がなくすぐに試せないのですが、これを試してみます。
    手詰まりとなっていたので、アドバイス頂けるのは大変助かります。

    なお大変心苦しい限りですが、具体的なDLLについてはお伝えすることができません。
    どうぞご容赦ください m(_ _)m

    Azuleanさんにコメント頂いたC++/CLI、Windows Forms への移行という点については、
    お客様側の意向というか、私の方では如何ともしがたい決定事項のようですが、
    Visual Studio 2012から非推奨となっていることは認識がありませんでした。
    私の方でも調べてみて、折りを見て関係者には進言してみたいと思います。

    2017年6月16日 19:15
  • Azuleanさんにコメント頂いたC++/CLI、Windows Forms への移行という点については、
    お客様側の意向というか、私の方では如何ともしがたい決定事項のようですが、

    要求の狙いを聞き出せて、かつ代案を提示して受けいられるか?ですね…。

    ・C++ 資産と組み合わせるため
    →別に GUI は C++/CLI である必然性はないはずなので、接続部分だけ C++/CLI でラップすれば OK

    ・VB.NET になじみがなく、C 系の言語にしたい
    →近い言語ということで、C# を提案してみる?

    ・単に C++ 化したい(C++/CLI を知らない)
    →C++/CLI は C++ と言えない&なぜ C++ なのかというあたりが気にかかる。
    純粋に C++ 希望なら、C++/CLI は使わないか、C++ で作った画面に、.NET の DLL を C++/CLI でラップしてつなぐという可能性もありうるか…?

    2017年6月16日 23:22
    モデレータ
  • プリプロセスの出力を有効(/P)にして問題のコードをコンパイルしてみました。

    出力された拡張子「.i」のファイルの情報量が膨大なので、見落としているかもしれませんが、
    Grepでざっと見た限りでは特に怪しげな部分は検出できていません。

    出力されたファイル内容は、ただの空行を除去するとおよそ8万行ほど出力されており、末尾の
    部分に今回の画面フォーム ヘッダファイルのソースがコメント除去されてほぼそのまま表れています。

    先頭からは延々と、ファイルの取り込みやマクロ展開?などが記述されていることが確認できますが、
    今回の問題エラーに関わる AA::BB::CC, AA:BB:II, foo については、プリプロセスの部分としては
    特に展開されていないようでした。

     ・「AA」で検索した時、末尾のソース本体部分(namespace宣言以降)で初めて出現。
     ・「II」、および「foo」で検索した時も同様。


    また試みに、コンパイルエラーとなる行をコメントアウトした時と有効化した時それぞれで、
    プリプロセスの出力を比較してみましたが、やはり末尾のソース部分に当該の行が出現する/しない
    の違いがあるだけで、他に差異はありませんでした。

    また明示的に#undefを試みる意味で、ヘッダファイル冒頭の
     #pragma once
     #include "Windows.h"
    に続けて、新たに
     #undef foo
     #undef AA::BB::II
     #undef AA::BB::CC
    の3行を追加してみましたが、これでもエラーは変わらず、やはり エラーC2365 となりました。

    プリプロセスの出力内容の解析は慣れていないので見落としがあるかもしれず、もう少し内容をよく
    確認してみようと思います。

    この点以外でも、もし何かお気づきのことがありましたらコメント追記頂けるとありがたいです。

    2017年6月17日 10:22
  • 具体的にコードを出してもらえない状況だと、これ以上のコメントを得るのは難しいかと思います。
    C++ が不慣れということですので、第三者が予想もつかないような記述ミスをされている可能性もありますので、フォーラムでの解決は難しいかと思っています。
    (現物のコードでなくても、再現可能なコードを別途作られてそれを元にできるなら可能性はあるかもしれません)

    同じ組織内の同僚・先輩など、そのソースコードに触れられて、C++、または C++/CLI に詳しい人に見てもらうしかないかと思います。

    -----
    余談

    gcnew AA::BB::CC(g); は通って、AA::BB::II^ foo = gcnew AA::BB::CC(g); は通らない。
    AA::BB::CC^ foo = gcnew AA::BB::CC(g); は通るのだろうか?

    再定義と言われるのなら、その部分はメンバー関数ブロックとみなされていない?
    そのメンバー関数だけでも、h に実装書くのではなく、cpp に実装を書くスタンスにすると変わる?変わらない?

    2017年6月17日 11:15
    モデレータ
  • 出力された拡張子「.i」のファイルの情報量が膨大なので、見落としているかもしれませんが、
    Grepでざっと見た限りでは特に怪しげな部分は検出できていません。

    実際にエラーが発生しているわけですから、何かしらの問題を見落としています。言語仕様と照らし合わせて、何が正しく、何が問題なのかを質問者さんが判断できないだけでしょう。

    当該のDLLを使ってVB .netで実装されていたアプリを、今回VC++に移行しようとしているものです。

    Azuleanさんも言及されていますが、もう一度。

    Visual C++ での互換性に影響する変更点(翻訳が微妙なので英語版も)には次のように記されています。

    Although we recommend that you do not create Windows Forms applications in C++/CLI, maintenance of existing C++/CLI UI applications is supported. If you have to create a Windows Forms application, or any other .NET UI application, use C# or Visual Basic. Use C++/CLI for interoperability purposes only.

    参考訳:
    C++/CLIを使用したWindowsフォームアプリケーションは作成しないことを推奨する、ただし既に存在するC++/CLI UIアプリケーションのメンテナンスはサポートされる。(訳注1: VC++2012リリース時のドキュメントなので「既に存在する」はVC++2010以前で作成されたものを指す。訳注2: 厳密にはVC++2010以前だが、実際にはVC++2010の新機能なので、VC++2010の1世代限りの機能である。)
    もしWindowsフォームアプリケーションやその他の.NET UIアプリケーションを作成するのであれば、C#かVisual Basicを使用すること。C++/CLIは相互運用の目的でのみ使用すること。(訳注3:「相互運用」は一般名詞ではなく.NET用語であることに注意。)

    ともかく5年前には既に使用するなとドキュメントで警告されている機能であることを自覚すべきです。それを踏まえてVisual C++を使用する指示なのか、C++/CLI言語を使用する指示なのか、どちらでしょうか? Visaul C++にはC++/CLI以外にもUIを作成する機能はあるため、両者は同一ではありません。

    もちろんC++言語に堪能であればこのような指摘はしません。あくまで「C++の経験が乏しい」とおっしゃられているからです。仮に質問の問題が解決できたとしても、今後いくつもの問題に直面することが予想されます。

    2017年6月17日 22:09
  • cpp上での実装など試してみましたが、残念ながら状況変わらずでした。


    ただし今回の質問に関して、C++/CLIに関してなど幾つも有用なアドバイスいただき、
    どうもありがとうございました。大変参考になりました。

    確認したところUIの実装として特段の要件はなさそうでしたので、今回のエラー以前に、
    まずプロジェクトの根本的な作り方から再度見直してみようと思います。
    このため、この質問はいったんここで締め切らせていただきます。

    ご回答、アドバイス頂いた方々、本当にありがとうございました。 m(_ _)m

    2017年6月19日 8:11