Microsoft Visual C++ 2010 Express 奮闘記


目次
第五章 以前
第六章 vc++ 2010 入門 2014/06/16
第七章 遠い道のり 2014/06/27
第八章 自力解決に挑戦 2014/06/30
 
メモ その1 変数宣言方法,その他
メモ その2 新規プロジェクト作成先ディレクトリ変更方法
メモ その3 他ファイルの include 設定方法
メモ その4 class, struct 定義の違い
メモ その5 マネージ型のクラス宣言
 ここで vc ⇒ vc++2010 Express SP1, vb ⇒ vb2010 Express SP1, vb6 ⇒ vb6 SP6 です。
 私のOS環境は WinXP Professional SP3 です。
 
第八章 自力解決に挑戦 2014/6/30
 < 第七章 > で書いた 「String^」 コンパイルエラー解決に (ググらずに) 自力で挑戦してみます。
 先ずは MSDL を確認します。
 「String^」 にカーソルを置いて ≪F1≫ を押下します。
 ところが表示されるのは < 「string」 > です。
 検索ボックスに 「String^」 と入力すると候補に 「c++」 が付加されるのでこれを使います。
 そして < 「String クラス 」 > に行き着きました。
 「String^」に関する事が書いてあり (ような気がする) ますが、私の力ではここからヒントを読み取ることができません。

 次の手段です。 新規プロジェクトで「Windows フォーム アプリケーション」を作ります。
 デフォルトで作成される 【Form1.h】 に以下を記述してコンパイルできることを確認しました。
public:
void Fn_Test(void) {
String^ w;
}
 同じく 【デフォルト.cpp】 に同じコードを記述します。 当然コンパイルエラーになると思ったら…。
 エッ! エ~ッ!! エ~~ッ!!! コンパイル出来ちゃった!!!!
 じゃ、< 第七章 > でのコンパイルエラーは何?

 再度 「struct Person」
struct Person
{
string name;
int age;
void show(); //メソッドの宣言
};
 を書いてコンパイルエラー内容を再確認してみると、
 「error C3265: マネージ 'name' をアンマネージ 'Person' で宣言できません。」
 なるほど、'Person' が アンマネージだからその中でマネージの 'String^型' を使えない、ということらしいです。
 コンパイルエラーメッセージの内容確認がとても重要だと再認識しました。
 私は 'マネージ','アンマネージ' の正確な内容は理解していませんが、vb でも良く出てくる単語なのでイメージでは理解できます。
 色々と試して見ます。
  1) 【Form1.h】 の 「public ref class Form1 : public System::Windows::Forms::Form」 にクラス変数として String^型 を置く ←OK
  2) 「struct Person」 を 「public ref struct Person」 に変える ←OK オッ、見えてきた
  3) 「public ref struct Person」 を 「public struct Person」 に変える ←NG なるほど
  3) 「public struct Person」 を 「ref struct Person」 に変える ←OK ヤッタ!
 つまりクラス変数として String^ を使用する場合には 「ref」 付きで宣言が必要、と現時点では理解しました。

 「ref」 宣言の意味を調べるにはさすがにググルしかありません。
 < C++/CLI入門 参照クラス - WisdomSoft > で以下を見つけました。
メモ その5 2014/6/30
 マネージ型のクラス宣言
 マネージ型のクラスを C++/CLI で実装します。基本的なクラスの書き方は標準 C++ と同じですが、
 クラスの宣言時に ref キーワードを指定し、インスタンス化には gcnew 演算子を用いなければなりません。

 C/C++ 言語による開発では、実行時にヒープ領域(すなわち new 演算子や malloc() 関数で生成したオブジェクト)に
 割り当てたメモリ領域は、不要になった時点で解放しなければなりません。 ※8-α
 何らかのリソースの解放を忘れてしまうと、プログラムはメモリを占有し続けてしまうメモリリークに繋がります。

 しかし、.NET Framework 専用の参照クラスを宣言すれば、このクラスのオブジェクトはランタイムによって管理されるため、
 明示的に破棄する必要がなくなります。オブジェクトが不要になった時点で、共通言語ランタイムが自動的に解放してくれるのです。
 ※8-αは知識としては知っていましたがどうやって管理したら良いのかを将来必ず悩むだろうと思っていましたがこれで解放されそうです。

閑話休題 2014/7/03
 マネージ と アンマネージ
 < C++/CLI入門 マネージ配列 - WisdomSoft > に以下のように書かれています。
 参照クラス型オブジェクトは、共通言語ランタイムによって管理されているマネージヒープ上に配置されるため、参照クラス型の配列を標準 C++ のネイティブ型の配列と同じように扱うことはできません。

 標準 C++ ネイティブのアンマネージ配列は、メモリアドレスが連続する記憶領域を物理的に確保するデータ配列でした。

 しかし、参照クラスのように共通言語ランタイムによって管理されているオブジェクトはプログラムからアドレス単位でアクセスすることはできません。マネージ型配列は論理的な配列であり、メモリ上に連続する物理的な配列ではないということを理解してください。マネージ型配列は配列の先頭へのポインタではなく、任意の数のオブジェクトの列を管理する配列オブジェクトを参照しています。
 vb の 「Protected Overridable Sub Dispose(disposing As Boolean)」 に 「マネージ状態を破棄します」,「アンマネージ リソース (アンマネージ オブジェクト) を解放し、」等のコメントが書かれている。

 「マネージ,アンマネージ」 をググってもどうしても理解できなかったが上記記事を読んでなんとなく感触を掴んだ。
 vb は基本的に全オブジェクトはマネージなのだと思う。
 しかし、vb で API を使ったり、c/c++ ネイティブで作った dll 等を使ったりすると アンマネージオブジェクトが生成されるのかもしれない。
 と、今は理解しておくことにします。
       
 
第七章 遠い道のり 2014/6/27
 namespace の使い方が判らない…。 トホホ…。
 フォームアプリケーションを作ると、以下の 【デフォルト.cpp】 ファイルが作られます。
#include "stdafx.h"
#include "Form1.h"

using namespace FormApp; //※7-α

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// コントロールが作成される前に、Windows XP ビジュアル効果を有効にします
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);

// メイン ウィンドウを作成して、実行します
Application::Run(gcnew Form1());
return 0;
}
 そして以下の 【Form1.h】 ファイルも作られます。
#pragma once

namespace FormApp { //※7-β

 << 途中省略 >>

}
 ※7-α で 「using namespace FormApp;」宣言しています。
 対応するのは ※7-β の 「namespace FormApp {」 です。
 【デフォルト.cpp】 ファイルを以下のように変えても問題ありません。
#include "stdafx.h"
#include "Form1.h"

// using namespace FormApp;

[FormApp::STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// コントロールが作成される前に、Windows XP ビジュアル効果を有効にします
FormApp::Application::EnableVisualStyles();
FormApp::Application::SetCompatibleTextRenderingDefault(false);

// メイン ウィンドウを作成して、実行します
FormApp::Application::Run(gcnew FormApp::Form1());
return 0;
}
 【Form1.h】 ファイルには Application は定義されていませんが親クラス System::Windows::Forms::Form にて定義されているのかもしれません。

 さて、以下のような 【Test.cpp】 ファイルを作成しました。  コンパイルは成功します。
#include <stdafx.h>

namespace NS_Test {
}
 そして 「using namespace NS_Test;」 を 【デフォルト.cpp】 に追記します。
 すると 「error C2871: 'NS_Test' : この名前を指定された名前空間は存在しません。」 コンパイルエラーが発生します。
 どうすりゃいいんだ…?

 何気に 【デフォルト.cpp】 に 「#include "Form1.h"」 が書かれていることに気がつきました。
 【デフォルト.cpp】 に 「#include "Test.cpp"」 を追記しました。
 「error C1083: include ファイルを開けません。'StdAfx.h'」 コンパイルエラーになりました。
 【Test.cpp】 の 「#include <stdafx.h>」 を 「#include "stdafx.h"」 に変更しました。
 ヤッター! コンパイルできました。
   「#include <…>」はNGで何故 「#include "…"」 ならOKか? は暫く放置します。
 vc では別ファイルは include が必要、と判りました。

メモ その2 2014/6/26
 新規プロジェクト作成先ディレクトリ変更方法
  メニューバー > ツール > オプション > プロジェクトおよびソリューション > プロジェクトの場所
 を、変更する。

メモ その3 2014/6/26
 他ファイルの include 設定方法
 追加したファイルは メモその2で指定したディレクトリ\新規プロジェクト作成時に指定した「名前」\新規プロジェクト作成時に指定した「名前」\ に作成される。
 デフォルトならば マイドキュメント\Visual Studio 2010\Projects\「名前」\「名前」\ フォルダに作成される。
 作成されたファイルを一つ上のディレクトリに移動する。
 つまり、メモその2で指定したディレクトリ\新規プロジェクト作成時に指定した「名前」\ に、
 デフォルトならば マイドキュメント\Visual Studio 2010\Projects\「名前」\ フォルダに移動する。
 この場合、「#include "..\移動したファイル名"」 とすれば良い。
 ソリューションエクスプローラー > ソースファイル に追加してある場合、一度「プロジェクトから除外」し、再度「既存項目の追加」で追加すること。

 MsgBox を使おうと考えました。
 ソースに MsgBox("Hellow World"); と書いても予想通りコンパイルエラー 「'MsgBox': 識別子が見つかりませんでした」 になります。
 で、問題はここから先の解決方法が判らない事です。
 MSDNを見ると次のように書かれています。
Interaction::MsgBox メソッド //※7-γ
 名前空間 : Microsoft.VisualBasic
 アセンブリ : Microsoft.VisualBasic (Microsoft.VisualBasic.dll 内)

[HostProtectionAttribute(SecurityAction::LinkDemand, Resources = HostProtectionResource::UI)]
public:
static MsgBoxResult MsgBox(
Object^ Prompt,
MsgBoxStyle Buttons,
>Object^ Title
)
 ※7-γ に注目してソースを Interaction::MsgBox("Hellow World"); と変更しましたが、
 「error C2653: 'Interaction' : 識別子がクラス名でも名前空間名でもありません。」になってしまいました。
 「Interaction」 を MSDN で調べると「 Microsoft.VisualBasic::Interaction」 となっています。
 ソースを Microsoft.VisualBasic::Interaction::MsgBox("Hellow World"); と変更すると
 「error C2882: 'Microsoft' : 式の中で名前空間の識別子が正しく使用されていません。」となります。
 もう今の私のレベルではお手上げです。

 しかたが無いのでグーグル兄貴に頼ります。
 すると 「System::Windows::Forms::MessageBox::Show("…");」 を見つけました。
 これを使えばコンパイルは成功します。
 「Microsoft.VisualBasic::Interaction::MsgBox」 の使い方は判りませんが、とりあえずはメッセージボックスが使えるようになりましたので良しとします。

 クラス内関数を使用したくて以下のソースを作りました。
class ClassTest{
public void Fn_Test(void) { //自作関数に 'Fn_' を付けるのは私の“癖”です
}
};
void Fn_Test(void) {
ClassTest1 ClaTest;
ClaTest.Fn_Test();
}
 「error C2144: 構文エラー : 'void' は ':' によって先行されなければなりません。」になります。
 何を意味しているのか全く判りません…。 トホホホ…。
判った!!!
class ClassTest{
public:
void Fn_Test(void) {
}
};
void Fn_Test(void) {
ClassTest1 ClaTest;
ClaTest.Fn_Test();
}
public, private はまとめて宣言するんだ!
 < はじめに > で 「これまでも C を勉強したことはあるので 基本文法は知っていました」 と書いたけど、本当は何も知らなかった事を痛感しています。
メモ その4 2014/6/27
 class, struct 定義の違い
 < C++のクラスをマスターしよう(前編)> から抜粋
 キーワードstructで定義したクラスのメンバは、既定ではpublicになります。
 クラスを定義するキーワードには、structの他にclassがあり、classを使って定義したクラスのメンバは、既定でprivateになります。classとstructの違いはこれだけです
 誤解を避けるために、public やprivate は必ず記述すべきだという意見もあります。この意見に従うなら、class とstruct を使い分ける必要はありません。



 もう、嫌になって来ました。
 あるページで以下のソースを見つけました。  「C++のクラスをマスターしよう」というのですから入門者用のページだと思います。
struct Person
{
string name; //※7-δ
int age;
void show(); //メソッドの宣言
};

//メソッドの定義
void Person::show()
{
// cout<<name<<" ("<<age<<")\n";
}
 何と ※7-δ でコンパイルエラーになりました。
 第六章 で書いた String^ に変えてもコンパイルエラーになります。
 どうせい、と言うんじゃ………………… (≧0≦)

 泣いていても埒が明きません。 気を取り直して…。
 先ず 「string」 コンパイルエラーを解決しました。
 < C++編【標準ライブラリ】 第2章 string > を見つけて
 「C++標準ライブラリには、文字列を安全かつ便利に扱える string という機能があります。
  これを使うには、string という名前の標準ヘッダをインクルードする必要があります。」 を発見しました。
 さらに < string型の使用ができません > により、
#include <iostream>
#include <string>
using namespace std;
 を記述すれば良い、と判りました。
 つまり ※7-δ
  1) 「#include <string>」 により、std::string が使用できる。
  2) 「using namespace std;」 により std:: を省略できる。
  3) 「cout<<name<<" ("<<age<<")\n";」 は <iostream> で使用可能。
 という、恐らくは 「vc 利用者なら当然ながら知っている」 内容が省略されている、ということなのでしょう。

 さて、次は String^ コンパイルエラーの解決に向かいます。
次へ> > 第八章 自力解決に挑戦
 
第六章 vc++ 2010 入門 2014/6/16
 第五章まで完了すればプログラムを開始できますがもう少し勉強します。
 「vc++ 2010 入門」 でググってヒットするページを読んでいきます。
  < Visual C++ 2010 Epxress の使い方 for 「プログラミング入門 ... >
    内容は 「太田研究室 | Visual C++ 2010 Express プログラミング入門」 と殆ど同じ。
    コマンドプロンプト で 「> chdir 」と打ち込んだ後、エクスプローラからフォルダを D&D すれば良い、ということを始めて知った。
    今までは全角名フォルダへの chdir ができずに困っていた。 (^^;

  < 初心者のための c++ 入門 vc++ 入門 c言語 入門 基礎から応用 ... >
    プログラムを全く知らない人を対象。
    経験者には冗長すぎるかも知れない。
    < 第1講 - 第5話 プログラミングをしよう >
    で、「label1->Text=L"はじめてのVisual C++";」という文が出てくる。
    ”->”は vb に慣れ親しんだ自分には非常に違和感がある。
    これを vb 風に ”.” に変えるとコンパイルエラーになる。
    又、「L"はじめてのVisual C++";」の ”L” を削除しても問題なく動く。
    ”L” が何を意味するか?

    < 第1講 - 第7話 バックアップの方法とソースを書くコツ >
    で、< ダウンロードファイルForm5.h > を丸々 C&P せよ、とある。
    図では「未項確定法」,本文では「末講確定法」,ダウンロードファイルでは「末項確定法」となっている。
    メールでは連絡したが、はたして直されるでしょうか…。
    

 色々と vc を触っている内に非常に違和感を覚える現象に出くわしました。
1)エクスプローラから vc ソリューションファイルをダブルクリックして起動させる。⇒ 図6-1
2)vc を起動させ 『最近使ったプロジェクト』 から選択する。⇒ 図6-2
3)vc を起動させ ファイル > 開く > ファイル から slnファイルを選択する。⇒ 図6-3
4)何かのソリューションを開いている状態で、ファイル > 開く > プロジェクト/ソリューション から slnファイルを選択する。⇒ 図6-4

図6-1

図6-2

図6-3

図6-4
クリックで拡大
と、普通にソリューションを開くことができます。
 しかし、何かのソリューションを開いている状態で、ファイル > 開く > ファイル から slnファイルを選択すると ⇒図6-5

図6-5  < クリックで拡大 >
    選択されたファイルはソリューション ファイルではありません
    現在のソリューションを閉じて、このファイルをソリューションとして開きますか?

と、なってしまいます。
 そのまま ≪はい≫ をクリックすればソリューションとして開けます。
 はたしてこれは 「問題(バグ)」でしょうか?
 私にとっては 「バグ」 です。 おそらく Microsoft にとっては 「仕様」でしょう。
 単に「≪はい≫ をクリックすれば開けるのだから良いではないか」 というものでは無いと思います。
 まぁ、無料品です。 我慢して使い続けるしかありません。
   ※しかし、有料版でも変わらないだろう、と私は思っています。

 < 初心者のための c++ 入門 vc++ 入門 c言語 入門 基礎から応用 ... > を読み続けます。
 < 第2講 - 第2話 挨拶ソフトのプログラミング > に、
    String^ w;
    w=L"はじめてのVisual C++";
というのが出てきました。
 私が知っている文字列代入方法は ※6-α
    char w[80];
    strcpy(w, "はじめてのVisual C++");
 というものです。
 私が C を苦手にしていたのはこの文字列操作に関してでして、char配列の大きさを超えて文字列を代入すると他のメモリーエリアに不正な情報が書き込まれてしまい暴走する。 ウィルスにはこの機能を使ってCPUを乗っ取ってしまうものがある、と覚えていた為です。
 Basic ならば文字列の境界を意識することは不要なので気楽に扱えていたのと比べてとても気が重かったのです。
 しかし vc ならば Basic 風に代入もできるし、文字列境界も気にしなくて良さそうです。
 ただ ※6-α だと 「label1->Text=w;」 にてコンパイルエラー 「1 番目の引数を 'char [80]' から 'System::String ^' に変換できません」 になります。
 コメント的には vb での CType 又は DirectCast が必要な気がしますが vc ではどうすれば良いのか全く判りません。
 道のりはとても遠いです。

 < 第2講 - 第3話 このプログラムのメリット > に、
    label1->Text=a+b+ある;
    としたのではエラーします。
    文字はL""というお洋服を着せなければならないというルールになっているからです。
 と書かれています。
 「a+b+ある」がエラーになるのは当然理解できます。 「ある」 が変数扱いになってしまいますから。
 しかし 「L」 の意味が相変わらず判りません。 「a+b+"ある"」 とすればエラーにならず実行結果もOKです。。
 初期の Basic では変数への代入には Let が必要でした。 その後 Let は省略可能になりました。
 この 「a+b+L"ある"」 の L も省略可能ということでしょうか?
 その内理解できれば嬉しいです。

 と、ここまで来てどうしても気になったので 「L""」 をググって見たところ次を発見した。
 < _T("")マクロだのL""マクロだのLPCTSTRだのの世界一詳しい解説 >
    Visual Studio2003までは標準設定がマルチバイトだったのでWindowsAPIや
    DirectX用の関数の引数に文字列を受け渡す時は
     TestFunc("文字列");
    みたいな感じでオッケーでした。
    しかし、Visual Studio2005からはこれではダメなんです。
    標準設定がユニコード設定なので多くの関数において文字列は
     TestFunc( L"文字列" );
      …
    のいずれかで受け渡さなないとダメです。
    一番上のL"文字列"はユニコード限定の文字列ですよ、という
    意味を表すマクロなので設定をマルチバイトに変更するとエラーになります。
 これで理解できた! 文字コードの問題なのか!
 とりあえずは プロジェクトプロパティ > 構成プロパティ > 全般 > プロジェクトの既定値 > 文字セット が 『Unicode文字セットを使用する』 となっている場合は L"" を使う、と覚えておく事にします。

 < 第3講 - 第2話 和のプログラミング > に従って次のように打ち込みました。
    lable4->Text=a.tostring;
 ミスが3つあります。
  1)lable ⇒ label
  2)tostring ⇒ ToString
  3)ToStringの後ろに () が必要
 1)を除いて、2),3)は vb ならば IDE(統合開発環境) が自動的に補ってくれる内容です。
 しかし vc の IDE は何もしてくれません。
 vb の IDE に 「小さな親切大きなお世話」 と思うことも多々ありますのでどちらが良い、とは言い切れませんが、vc の道のりは相当に遠い、という事だけは判りました。

メモ その1 2014/6/18
 変数宣言方法,その他
int i, j=5, k; //①
for (i = 1; i <= 10; i++) { }
for(int L = 1; L <= 10; L++) { //②
int i=0, j; //③
j = ++i;
}
if ( k <= j ) {
// } else if ( j =< k ) { ④
} else if ( k >= j ) {
// } else if ( k => j ) { ⑤
} else {
} //if
 ① 変数初期化は宣言中にて可。 vb と違い続けて変数宣言を記述可能。
 ② ループ内で変数型宣言すれば非宣言変数使用可能。
 ③ 子ブロックにて親ブロックと同じ変数名宣言可能。親ブロック変数に影響無し。
 ④ イコールレスザン使用不可。 レスザンイコールを使用すること。
 ⑤ 同じくイコールグレーターザン使用不可。 グレーターザンイコールを使用すること。
 ④,⑤ 但し私はレスザンイコールしか使用しない。

 いくつか「vc++ 2010 express 入門」 でヒットするページを読みましたが、どうも私の好みのページが在りません。
 vb を始める時に最もお世話になったのが < 改訂版 プロフェッショナルVB.NETプログラミング > です。
 こんな感じで1から10まで教えてくれる入門ページがあると助かるのですが…

次へ> > 第七章 遠い道のり