トップ回答者
CLIでの、private による値の隠ぺいについて

質問
-
.NET2005 VISTAです。
以前、質問して、その時は「できた」と思ったのですが、まだ分からないことがあり、スレッドを改めて、質問します。
教わったのは、配列の長さが固定長のものと、可変長のものですが、
可変長については
Form1.hprivate: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
//■リストにする方法
List book;
book.Add(gcnew Record("ここ","ねこ"));
book.Add(gcnew Record("そこ","いぬ"));
book.Add(gcnew Record("あそこ","きつね"));
book.Add(gcnew Record("どこか","たぬき"));for ( int i = 0; i < book.Count; ++i ) {
Console::WriteLine(L"{0} に {1} がいます", book[i]->GetAddress(), book[i]->GetName());
}}
Record.hnamespace dataclass {
using namespace System;
using namespace System::Collections::Generic;
ref class Record {
private:
String^ address;
String^ name;
public:Record(String^ a, String^ n) : address(a), name(n) {}
void SetAddress(String^ value){ address = value; }
void SetName(String^ value){ name = value; }
String^ GetAddress(void){ return address; }
String^ GetName(void){ return name; }
};}
固定長のコードは、
Form1.hprivate: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
array^ addressBooks = gcnew array(10);
//その最初の要素にインスタンスを代入
addressBooks[0] = gcnew AddressBook();
addressBooks[1] = gcnew AddressBook();
//address と name を設定
addressBooks[0]->SetAddress("Somewhere");
addressBooks[0]->SetName("TheName");
addressBooks[1]->SetAddress("Somewhere1");
addressBooks[1]->SetName("TheName1");};
}Record.hnamespace dataclass {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;ref class AddressBook
{
private:
String^ address;
String^ name;
public:
void SetAddress(String^ value){ address = value; }
void SetName(String^ value){ name = value; }
String^ GetAddress(void){ return address; }
String^ GetName(void){ return name; }
};}
ところが、今頃気づくのもどうかと思うのですが、これですと、いずれも、
button1_Clickの中で配列を宣言/定義しているので、button1_Clickの中でしか使えません。
宣言/定義をForm1.h の上の方にもっていけばいいのかな、と思ったのですが、
「公開されたメンバのシグネチャはアセンブリ プライベート型 AddressBook' を含んでいます。」
というようなエラーになって、ビルドを通りません。
クラスとして宣言する必要があるのかと思いましたが、書式が分かりません。
いろいろ試していても、結局最後は「ヘタな鉄砲、数を撃っても当たらない」になってしまって、煮詰まりました。
アドバイスをお願いいたします。
回答
すべての返信
-
初々心者 さんからの引用 Form1.hの先頭で Record.h をインクルードしている以外は、これだけです。
うそん・・・。自動的に生成されたコードが、他にも、いろいろあるでしょーよ。そこに、いくらでもヒントが隠れているはず。少しは「考えて」ください。「考えずにやる」=「数撃つ」になるんです。
例えば、クリックしているボタンだって、メンバーの変数として宣言されているでしょう? こんな感じで
private: System::Windows::Forms::Button^ button1;
これのまねをすればいいじゃないですか。
初々心者 さんからの引用 C++から入っているので、それ以外だと、コードはちょっと違うのかもしれません。
基本的に同じです。(VBだって、C#だって、基本的に同じです。キーワードと記号が違うだけ。)
-
初々心者 さんからの引用 Form1.hの先頭で Record.h をインクルードしている以外は、これだけです。
しているのであれば、その記述を載せてくれませんか?
(しているなら「これだけ」というのは偽りになる。)
array^ addressBooks = gcnew array(10);というのはできない。インスタンスの作成はコンストラクタ(とかに)に記述しないとだめ。
また array^ addressBooks ではなくarray<AddressBook^> addressBooks としないとコンパイルできないはず。(Listのほうも)
(「載せられたコードはどれもコンパイルできませんし」と書いたのはその意図があったのですが、、、)
していないのであれば、つかえるはずもありません。
-
外池です。重大な誤解というか、重大なすれ違いのないように、お断りしておきます。
回答している方々は、みなさん、「考え方」を示すためにだけ、ごく要点のみを書いておられます。コードの例示もそうです。そのままコンパイルが通るとは限りません。初々心者さんご自身で、適切に修正して、使ってください。「適切に修正」のときに、よく考えてください。
逆に、回答している方々は、初々心者さんは、コンパイルして実行結果を見ながらいろいろ考えておられると想定しています。ドキュメントを読んで基本的なところは理解できるレベルであると考えています。(C++の経験は十分にあると思っています。)
問題への取り組み方で、そもそもの事実誤認があるようでしたら、今の時点で仰ってください。(すでに、何度も、疑念を示す発言は回答者からは出ていますが)
-
改めて、何度も見直しましたが、これで全部だと思います。
私の環境では、これで、動いています。
細かいことを言えば、値が取得されていることを確認するため、テキストボックスを置いて、
末尾に、textBox1->Text = addressBooks[1]->GetAddress();というようなコードを置いていますが。
もともとのスレッドのやりとりはこれです。
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2749205&SiteID=7
例示のコードは、この中で、επιστημη さんと、Abstract さんに教わったものです。
button1_Clickの中で宣言/定義しているので、ローカルの扱いになっている、と思ったのですが。
-
今回のスレッドでのご質問は、List Bookや、array Addressbookを、イベントハンドラの中のローカル変数ではなくて、Form1のクラスメンバー変数として宣言したいけれども、上手くいかない。どうすればよい? というご趣旨だと思いますが?
私からの回答は、Button1やTextBox1も同様にForm1のクラスメンバー変数で宣言されているものなので、その宣言されている場所を見つけて、まねして書いて下さい、と申し上げています。ソースコードが、アウトラインモードとかで折りたたまれて、見えない部分があるかもしれませんが、全部展開して見てみてください。
##本当に、private: System::Windows::Forms::Button^ button1; の行、ないですか? ##
一度、プロジェクトを全部閉じて、Form1.hのファイルを普通のメモ帳とかで開いてみると、見つかるかもしれません。万一、複数のヘッダーファイルがあるようだったら、全部、しらみつぶしに調べてみてください。
-
初々心者 さんからの引用 改めて、何度も見直しましたが、これで全部だと思います。
私の環境では、これで、動いています。
ビルドできません。
> array^ addressBooks = gcnew array(10);
だけでエラー 1 error C2955: 'cli::array' : クラス テンプレート を使用するには テンプレート 引数リストが必要です。
エラー 2 error C2662: 'cli::array<Type,dimension>::array' : 'cli::array' から 'cli::array<Type,dimension> %' へ 'this' ポインタを変換できません。
とエラーが出ます。
私の環境も Windows Vista/Visual Studio 2005 SP1です。
実際どのような記述をしているのでしょうか?
載せられたコードはどれもコンパイルできませんし、提示されている情報が不足しているかもしれません。
回答がもらえないようなら、私はおります。
-
外池です。
arrayとListについては、蒼の洞窟さんの質問にある通りです。コンパイルが通るなら通るで結構です。じゃぁ、そのときのarrayやListは、どのクラスに基づいているのか示してください。
abstractさんのコメントについては、初々心者さんの推察のとおり、 RecordクラスをForm1クラスの中に入れ子にする必要は、特にありません。Form1と対等に別のところで宣言してもかまいません。
次に、Form1.hに存在するべきコードです。ごくごく単純にForm1にひとつボタンを貼り付けただけで、以下のとおりのコードが自動的に生成されます。(行数を減らすために、一部省略しています) これらの記述が見つからない、と仰るようであれば、すいません、私もついていけません。これらがなければ、そもそも、Form1とボタンの表示は無理なはずです。
Code Snippet#pragma once
namespace cppclr {using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;/// Form1 の概要
/// 警告: (外池により省略)
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//TODO: ここにコンストラクタ コードを追加します
}protected:
/// 使用中のリソースをすべてクリーンアップします。
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ button1;//<---ここにbutton1の宣言アリ(外池)
protected:private:
/// 必要なデザイナ変数です。
System::ComponentModel::Container ^components;#pragma region Windows Form Designer generated code
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
void InitializeComponent(void)
{
this->button1 = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// button1
//
this->button1->Location = System::Drawing::Point(8, 8);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(64, 24);
this->button1->TabIndex = 0;
this->button1->Text = L"button1";
this->button1->UseVisualStyleBackColor = true;
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(292, 273);
this->Controls->Add(this->button1);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);}
#pragma endregion
};
}ご健闘をお祈りします。
-
たいへん失礼しました。
固定長のコード Form1.h での配列の宣言、ご指摘の通り、
array^ addressBooks = gcnew array(10);
ではなく、
array<AddressBook^>^ addressBooks = gcnew array<AddressBook^>(10);
でした。
また、List book; は、List<Variable^> table;です。
コードの記載漏れがないかばかり見ていて、コードの内容の間違いに気づきませんでした。
あちこち、コピペしているうちに飛んでしまいました。
すぐ直したのですが、スレッドにコピペした時が間違いで、それに気づきませんでした。
申し訳ありません。
-
固定長のコード
Code Snippet/// <summary>
/// Form1 の概要
///
/// 警告: このクラスの名前を変更する場合、このクラスが依存するすべての .resx ファイルに関連付けられた
/// マネージ リソース コンパイラ ツールに対して 'Resource File Name' プ/// 変更する必要があります。この変更を行わないと、
/// デザイナと、このフォームに関連付けられたローカライズ済みリソースとが、
/// 正しく相互に利用できなくなります。
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{public:
////////////////////////////////////////array<AddressBook^>^ addressBooks = gcnew array<AddressBook^>(10);
////////////////////////////////////////
Form1(void)
{
InitializeComponent();
////TODO: ここにコンストラクタ コードを追加します
//
}配列の宣言をここに置いた時、
公開されたメンバのシグネチャはアセンブリ プライベート型 'dataclass2::AddressBook' を含んでいます。
ref クラス または値型の内部で、スタティック データ メンバのみ初期化することができます
というエラーになります。
これ以外にも、
addressBooks[0] = gcnew AddressBook();
addressBooks[1] = gcnew AddressBook();も含めて、あちこち置いてみましたが、解決しませんでした。
可変長の場合も、
List <Variable^> book;
を、同じところに置いて、
'book': 公開されたメンバのシグネチャはアセンブリ プライベート型 'CLIdataclass::Variable' を含んでいます。
というエラーになります。
「< > 記号は、なぜか中身ごと消える時があります。」の意味は理解しました。
アドバイス、ありがとうございました。
-
外池です。私のコメントは#全然#参考にしてもらえてないんでしょうかねぇ。
(やっぱり、あるんじゃないですか! 自動生成のコードの部分。ナイナイ、ばかり言ってて、信用できねぇ)
で、button1の宣言と比べてみてください。button1は宣言のところで、いきなり、gcnewの代入をしてないですよね? まずは、gcnewの代入はせずに、変数の宣言だけしてください。で、別の場所で、宣言した変数に対して、gcnewを使った代入をしてください。(これは、2行目のエラー対策)
あと、privateなクラスで宣言したものを、publicな変数に宣言することはできません。(これは1行目のエラー対策)
-
いや、だから、
Code Snippetpublic:
/////////////
array<AddressBook^>^ addressBooks = ...
/////////////
Form1(void)
{おもいっきり public ですけど。
コードを、書いたほうがいいですか?Code Snippetprivate:
array<AddressBook^>^ addressBooks;
public:
Form1(void)
{
InitializeComponent();addressBooks = gcnew array<AddressBook^>( 10 );
}これでいかが?
-
たいへんありがとうございました。
Code SnippetForm1(void)
{
InitializeComponent();
////////////////////////////////////////////
addressBooks = gcnew array<AddressBook^>( 10 );
addressBooks[0] = gcnew AddressBook();
addressBooks[1] = gcnew AddressBook();
////////////////////////////////////////////
}で、button1_Click 関数で代入した値を、button2_Click 関数で取り出すことに成功しました。
List のほうも、応用で、成功しました。
-
動いたのは慶事であると存じます。
まぁそれはいいんですが、> 公開されたメンバのシグネチャはアセンブリ プライベート型 'dataclass2::AddressBook' を含んでいます。
> ref クラス または値型の内部で、スタティック データ メンバのみ初期化することができます何故、コンパイラがこんな事を言ったのか、理解できていますか?
できれば、貴方なりの言葉で構いませんから、ご説明願います。(説明したくないなら、しなくていいです)
本当は、
「説明できるようになるまで先に進んじゃいかん」
と言いたいところですが、止める権利は誰にもありませんので、進みたいならどうぞ。ただし、
コンパイラの言っている事を理解できなきゃ、同じエラー(と質問)を繰り返すことになりますよ?私は諸事情あって今は時間余ってるから幾らでも回答しますけど、
貴方にとっては決して良いことではないと思います。正直なところ、貴方の C++ の理解度がどんなものか、測れずにいます。
-
Abstract さん、ありがとうございます。
> 何故、コンパイラがこんな事を言ったのか、理解できていますか?
実は、1個前のアップで、そのことを質問しようと思ったのですが、
余分なことは書かないほうがいいような気がして、削除してしまいました。
MFCだと、クラスや構造体を、外部変数を宣言するのと同じように、ど~んと宣言してしまえば、
変数自体が private であっても、publicなget*** やset*** を使って、自由に値を出し入れできます。
ですから、宣言を private にする、ということ自体がピンときませんでした。
(public の後で宣言する、というのも、考えてみれば同じことなのですが、「宣言はあのあたり」というのはなんとなくわかりました。)
今回のコードでは、クラスそのものを宣言している訳ではなく、private なメンバである address やname を宣言している
のですから、当然の帰結として、private になるのかと、思いました。
MFCだと、
***View.cppで、
Code Snippetclass AddressBook aa[10];
AddressBook *p;と、ついでにポインタまで宣言しておいて、
(aa 自体がポインタですが、安全性の問題で aa はなるべく触りたくないので)
***.hで、
Code Snippetclass AddressBook{
private:
char address[80], name[80];
public:
void setlinkName(CString ss); void setname(CString ss);
CString getaddress(); CString getname();
};
extern class AddressBook aa[10];
extern AddressBook *p;として、あとは、***.cppで、set***、get***の中身を書けば、自由に値の出し入れができます。
構造体なら、もっと簡単です。
ポインタとアロー演算子を使う方法は、以前のアップで επιστημη さんが「一般的でない」とおっしゃっていましたが、
私はそれで慣れているので、使っています。
この場合、クラスそのものを extern で、オブジェクト全体に向かって宣言したことになりますから、address や name は、
クラスの中で宣言すればそれで足りてしまいます。
-
Abstractさんの問いかけに対して、全然、答えになっていません。
オブジェクト指向プログラミングの考え方のご高説と、(privateと修飾できる機能をどのように活用すべきかということ。MFCのことだったら承知しているような書きぶりですが、まったく、意味をなしていません。)
ご高説がどうであろうと言語の仕様で宣言に仕方が定められていることと、(間違った書き方をしたら、コンパイルが通らない)
まったくゴチャゴチャです。
お願いですから、キチっとした教科書を手に入れて、系統的に勉強してください。
「なんとなくあの場所が座りがいいような気がしました」なんて、あきれて、開いた口がふさがりません。二度とこのような言葉は、このフォーラムでは使わないでください。
-
MFCだったらexternを使わず、CXXXAppクラスにアプリ全体で使う変数を用意して使うのが普通だと思うのですが。
(externを使う記述はどっちかといったらC言語よりかなぁと。)
XXXX.h
Code Snippet#include "AddressBook.h"
・・・
class CXXXApp : public CWinApp
{
public
AddressBook aa[10];
・・・
};
で使うときに
CString s = ((CXXXApp*)AfxGetApp())->aa[0].getname();
とか
CString s = theApp.aa[0].getname();
とかして取得する。
-
蒼の洞窟さん、ありがとうございます。
リビルドの件では、たいへん失礼いたしました。
申し訳ありません。
> MFCだったらexternを使わず、CXXXAppクラスにアプリ全体で使う変数を用意して使うのが普通だと思うのですが。
もともとは、林晴比古先生の、「新C++言語入門」に載っていたと思うのです。
(記憶違いがあるかもしれません)
extern で複数のクラスで値を取得できるようにしたのは、我流だったような気がします。
クラスをそのままファイル入出力するという、悪いクセがついてしまったこともあって、そのまま使い続けることになりました。
(さすがにクラスをそのまま読み書きするのは、色々な人に忠告されてやめましたが)
新しいアプリを作る時、オブジェクト指向 「まるだし」で、コピペして、ちょこちょこっと直せば廃物利用できるという
便利さもあります。
そもそも論的には、値は、すべてドキュメントクラスで扱うべきものでしょうが、私には、なんだか使いにくいです。
ご例示のコードですが、AddressBook aa[10]; はpublic になっていますが、name や address が private の場合は、
AddressBook aa[10]; も private になるのでしょうか。
-
初々心者 さんからの引用 クラスをそのままファイル入出力するという、悪いクセがついてしまったこともあって、そのまま使い続けることになりました。
(さすがにクラスをそのまま読み書きするのは、色々な人に忠告されてやめましたが)
PODなクラスであればクラスをそのままファイルにバイナリで出力してもよいのですが(ポインタがメンバ変数だと読み込み時にまずいが)、
それ以外の場合たとえばクラスをメンバに持つとか仮想関数があるクラスだとこの方法はだめです。
初々心者 さんからの引用 そもそも論的には、値は、すべてドキュメントクラスで扱うべきものでしょうが、 その値の使われ方によります。
ドキュメントクラスのほうが良いこともあるし、アプリケーションクラスのほうが良いこともある、ケースバイケースです。
初々心者 さんからの引用 ご例示のコードですが、AddressBook aa[10]; はpublic になっていますが、name や address が private の場合は、
AddressBook aa[10]; も private になるのでしょうか。
いいえ。C++の入門書のアクセス指定子のところをよく読んでください。
理解するときには最低限のコードを書いてみるとよいでしょう。
-
なんか、回答の方向性が全然違ってる気がしますが、まぁいいでしょう。
その後の文章で、なんとなく理解度が見えました。それと、なぜ貴方が addressBooks に対して private を指定しなかったのか、ようやく理解(想像?)できました。
address や name が private だから、addressBooks も private になるだろう、という事ですね?
これに関しては、蒼の洞窟さんもおっしゃっていますが、アクセス指定子について勉強してください。
「アセンブリ云々」のエラーについては CLI の話ですけど、たぶん関連で理解できるようになるでしょう。そうして、それについて勉強して、理解したならば、
貴方が今まで重大な勘違いをしていた事に気付くでしょう。
頑張って下さい。
-
外池です。あの・・・、正直なところ、お伺いしたいです。
蒼の洞窟さんや、Abstractさんは、初々心者さんの言葉遣いを理解できるんでしょうか? できてるんだったら、すごいです。
>MFCだと、***View.cppで、
> class AddressBook aa[10];
> AddressBook *p;>と、ついでにポインタまで宣言しておいて、
>(aa 自体がポインタですが、安全性の問題で aa はなるべく触りたくないので)
って・・・・???
私は、MFCには疎いので、よくご存知の初々心者さんに、丁寧な言葉づかいで、この部分の解説をお願いしたいのですが。
質問1) ***View.cppでこの宣言をする理由は? そして、この宣言は、***View.cppのどこに書けばよいのですか?
質問2) aa[10]は、何のクラスの配列になるんですか? 私には、最初のclassと書かれている意味が解らないので教えてください。
質問3) ポインタaaが指す位置と、ポインタpが指す位置が同じなんですか? 同じだとすれば、そうなる理由はこの2行からどのように読み取ればよいのですか?
あの・・・、失礼ながら、もし、蒼の洞窟さんや、Abstractさんがご理解されているなら、ご教示ください。お願いします。
-
Abstractさん、蒼の洞窟さん、ありがとうございます。
一晩、よく考えようと思ったのですが、早くアップしたほうがいいような気がして、書きました。
「なぜaddressBooks に対して private を指定しなかったのか」の理由は簡単で、問題意識が全くなかったからです。
今まで、重要な配列は、クラスや構造体にして、そのまま宣言していたので、そもそもアクセス演算子が問題になったことがありませんでした。
AddressBookクラスの内容は、
private なメンバ変数 address と name と、
public なメンバ関数です。
で、問題の private に宣言しているのは、
array<AddressBook^>^ addressBooks;
です。
ここで、改めて 「addressBooks ってなんだ?」 ということになりました。
感じとしてはポインタみたいですが、宣言にアスタリスクがありません。
構造体の用法でこんなのがあったような気がして、参考書をひっくり返しているのですが、
今のところ見つかりません。
アクセス演算子は、蒼の洞窟さんのおっしゃる通り、手持ちの参考書を全部見てみましたが、
ヒントになるようなことは、何も書いてありませんでした。
近所に、それなりに大きな本屋はあるのですが、CLIの参考書は、本当に見つかりません。
1冊、C#の参考書がありましたが、私自身がC#を全く知らないので、躊躇して、次に行った時は、
もう売れてしまっていました。
八重洲のブックセンターに行って来ようと思っていますが、1日がかりになってしまうので、まだ果たせずに
います。
ただ、それは「いい訳」にしかなりません。
とりいそぎ、ご一報します。
引き続き調べます。
-
質問1) ***View.cppでこの宣言をする理由は? そして、この宣言は、***View.cppのどこに書けばよいのですか?
別に***View.cppでなくても、かまわないかもしれません。
試したことはありませんが。
要は、値をどのクラスで使うかです。
詳しくはC++の参考書を読んでください、としかいいようがありません。
質問2) aa[10]は、何のクラスの配列になるんですか? 私には、最初のclassと書かれている意味が解らないので教えてください。
aaは、クラスに置く値の、メモリ上のアドレスです。
aa[5]であれば、aaの5番目のメンバのセットのメモリ上の番地です。
class AddressBook aa[10];と宣言すれば、aa番地から、メンバ10セット分のメモリを確保したことになります。
質問3) ポインタaaが指す位置と、ポインタpが指す位置が同じなんですか?
当然、p=aa; は必要です。
C++は、ポインタとインクリメント演算子で、高速処理をします。
というか、変数を介さずに、直接、値の保持されているメモリの番地にアクセスすることで、高速処理をします。
うかつにポインタとデクリメント演算子を組み合わせると、暴走します。
ここはC++の掲示板で、このスレッドでは、私が質問者だと思うのですが。
-
外池 さんからの引用 質問2) aa[10]は、何のクラスの配列になるんですか? 私には、最初のclassと書かれている意味が解らないので教えてください。
C言語時代はstruct AAA { };と定義した場合、AAA型を使う際にはstructを省略できませんでした。
C++では省略することができますが、省略しないこともできます。
同様の原理で、class AAA { };も(AAA型を使う際には)classの有無が自由になっています。
Code Snippetclass TestClass
{
private:
int a;
};int _tmain(int argc, _TCHAR* argv[])
{
class TestClass arrayClasses[10];return 0;
}※VC++2005でコンパイルが通ります。お確かめ下さい。
これを踏まえて、class AddressBook aa[10];は別途宣言のあるAddressBookクラスの10個の配列と想像することができます。
#その下の行はなぜclassキーワードがないのかというのは謎でしかありませんが。
-
初々心者 さんからの引用 ここで、改めて 「addressBooks ってなんだ?」 ということになりました。
感じとしてはポインタみたいですが、宣言にアスタリスクがありません。
ポインタに似たような存在です。
CLIでの参照型になりますので、C++の参考書を探してもでてきません。
初々心者 さんからの引用 アクセス演算子は、蒼の洞窟さんのおっしゃる通り、手持ちの参考書を全部見てみましたが、
ヒントになるようなことは、何も書いてありませんでした。
public: private: protected:はC++の参考書なら必ず触れていると思うのですが。
細かい仕様まで書いていないことはありますので、private:にしたものが外部からアクセスできるかどうか試してみて理解を深めるのも一手ではないかと思います。
初々心者 さんからの引用 近所に、それなりに大きな本屋はあるのですが、CLIの参考書は、本当に見つかりません。
和書でC++/CLI専門に扱った本は中さんの「実践C++/CLI 極めるための基礎と実用テクニック」ぐらいなんじゃないでしょうか?
本屋で見つからないのであれば、Amazonやbk1等の通販でどうぞ。
私的意見ですが、C++である程度経験を積んだ上でないと、C++/CLIは非常に困難だと思います。
このエラーや仕様はC++/CLI固有なのか、C++でもあり得るのかという判断もつかないですし…。
#C++/CLIでGUIを組むのは苦痛です。(VBやC#に対するメリットが薄い)
#GUI部分はC#で実装し、アンマネージのライブラリ部分をC++/CLIといった棲み分けが効率的だなぁと感じています。
-
初々心者 さんからの引用 質問1) ***View.cppでこの宣言をする理由は? そして、この宣言は、***View.cppのどこに書けばよいのですか?
別に***View.cppでなくても、かまわないかもしれません。
「別に***View.cppでなくても、かまわないかもしれません。」ということでは、貴方にはCViewクラスの意味がわかっていないのだと思います。ちなみに、C++の参考書を読んでも、CViewクラスのことは書いていません。MFCはクラスライブラリーであって、C++の本質ではありません。
C++がMFCと同義だと思っていることが、貴方の勘違いであることを、早く自覚してください。
初々心者 さんからの引用 質問2) aa[10]は、何のクラスの配列になるんですか? 私には、最初のclassと書かれている意味が解らないので教えてください。
aaは、クラスに置く値の、メモリ上のアドレスです。
aa[5]であれば、aaの5番目のメンバのセットのメモリ上の番地です。
class AddressBook aa[10];と宣言すれば、aa番地から、メンバ10セット分のメモリを確保したことになります。
「クラスに置く値」という表現はよくわかりません。「置く」の意味を教えてください。で、実際、どのクラスの中に置かれているのでしょう? この場合に・・・。
そもそも、私の質問は「何のクラスの配列になるのか?」というものでしたが、回答いただけませんでした。また、最初にclassと書かれている意味もお尋ねしましたが、回答していただけませんでした。classと書くことの意味に関しては、Azuleanさんからご回答をいただき、理解できましたが、貴方は、classを書くべきか、書かなくてもよいのか、理解できていないことがわかりました。
aa[5]の意味は私も知っています。配列の宣言以外の場所、つまり、式の中では、aaはメモリ上のアドレスを指し、*aaが、そのメモリに格納されている値を表します。aa[5]は、正しくはメモリの番地ではありません。5番目でもありません。aa[5]とは、aa[0]、aa[1」、...、aa[5]と、6セット目のアドレスに格納されている「値」を表します。AddressBook a[10];と宣言したばあい、AddressBookクラスのオブジェクトを「参照」できる変数10個分のメモリを確保したことになり、実際に使えるのはa[9]までです。(aa[5]が5番目と言っているようだと、aa[10]を使ってしまいますよ? -> 暴走)
「メンバ10セット分」という表現は不適切です。配列の要素のことはメンバとは呼びません。また、AddressBookクラスのオブジェクト自体のためのメモリは、まだ確保されていません。
初々心者 さんからの引用 質問3) ポインタaaが指す位置と、ポインタpが指す位置が同じなんですか?
当然、p=aa; は必要です。
その一行を書かなければ、このような宣言はまったく意味をなしません。
初々心者 さんからの引用 C++は、ポインタとインクリメント演算子で、高速処理をします。
というか、変数を介さずに、直接、値の保持されているメモリの番地にアクセスすることで、高速処理をします。
うかつにポインタとデクリメント演算子を組み合わせると、暴走します。
知っています。インクリメント演算子でも同じ危険はつきまといます。加・減算もできるしやはり危険はあります。なぜ、aaをいじらずにpを操作すれば安全と言えるのですか? pの操作をあやまれば、暴走するのではないですか?
暴走とは具体的になんでしょうか? よく知っている人であれば、アクセスしてはいけないメモリ領域に踏み込むからだ、と答えられるはずです。で、最近のOSであれば、大抵、メモリ保護違反という形で、そのアプリだけを停止し、マシン全体の暴走は食い止めるようになっています。
初々心者 さんからの引用 ここはC++の掲示板で、このスレッドでは、私が質問者だと思うのですが。
そのとおり、C++の掲示板であって、貴方のC++に関する知識のレベルを試してみました。
試すということは、非常に悪いことです。このことは、真摯にお詫びします。しかし、貴方が用語だけを振り回して知ったかぶりをしているがために、簡単な解決が可能な問題に多くの労力が割かれていることも、かなりの罪だと私は思います。まったく建設的じゃないからです。
貴方には自覚が必要です。どこがわかっていないか、何を勉強すべきか。いかがです? わかっていないことは、今から勉強すればとりかえせます。「わかっていない」ということを自覚していないことは深刻です。
-
外池 さんからの引用 AddressBook a[10];と宣言したばあい、AddressBookクラスのオブジェクトを「参照」できる変数10個分のメモリを確保したことになり、実際に使えるのはa[9]までです。(aa[5]が5番目と言っているようだと、aa[10]を使ってしまいますよ? -> 暴走)
「メンバ10セット分」という表現は不適切です。配列の要素のことはメンバとは呼びません。また、AddressBookクラスのオブジェクト自体のためのメモリは、まだ確保されていません。
この部分が何か間違っているような予感がしてなりません。
AddressBook *a[10];に対する説明ならば、この記述で納得しますが…。
-
Azuleanさん、ご指摘ありがとうございます。そうでしたわ、話の基点は、初々心者さんが「MFCの場合は」という前提で書かれたコードでしたね。そしたら、素のC++ですね。
調べてみます。C++のクラス型の配列宣言について
-----(追記) お詫びと訂正 -----
標準のC++において、AddressBookクラスの配列aa[10]を「AddressBook aa[10];」と宣言する場合においては、AddressBookクラスのオブジェクトに必要なメモリが、10個分確保される。(「標準」と言ってよいか微妙ですが。C++プライマー第2版による) aaはその先頭を指すポインターである。
この場合、用いられるメモリが、スタックか、ヒープかは、文脈による。(関数の中のローカル変数としての配列ならスタック。上位のオブジェクトのメンバーとしての配列でそのオブジェクトがヒープに存在するなら配列もヒープ)
CLRのクラスと混同していました。私の理解の整理が不十分だったことによる誤りです。お詫びします。
----改めて、捕捉。以下の説明は、CLRにおける「array<AddressBook^>」の宣言や用法の説明になります。
「array<AddressBook^>^ addressBooks;」と宣言すれば、AddressBookクラスのオブジェクトへの「参照」を複数格納できる配列を宣言したことになるが、配列の要素を格納する場所は、まだ確保されていない。
「addressBooks = gcnew array<AddressBook^>(10);」によって、10個分の要素のためのメモリーがヒープに確保された。ただし、上述のとおり、個々の要素は「参照」である。個々のAddressBookクラスのオブジェクトそのものも、まだ、用意されていない(メモリは確保されていない)。
「addressBooks[n] = gcnew AddressBook();」によって、新しいAddressBookクラスのオブジェクト(インスタンス)が用意され、それへの参照が要素n(値は0~9のいずれか)に格納された。
----こんな感じでよろしいですかね?
厳密を期するために、チェック頂ければ幸いです。ご指摘を頂いたら、この記事の編集によって対応したいと思います。
-
外池 さんからの引用 Azuleanさん、ご指摘ありがとうございます。そうでしたわ、話の基点は、初々心者さんが「MFCの場合は」という前提で書かれたコードでしたね。そしたら、素のC++ですね。
通常のC++も、C++/CLIも、AddressBook aa[10];なら10個のAddressBookのインスタンス(実体あり)です。
参照にはなりません。
C++/CLIでのいわゆる参照型はBitmap^のように"^"がつきます。
Bitmap^型の配列はarray<Bitmap^>^のようになります。
#注:C++/CLIでは確か、Bitmap等の参照型もスタックに取ることができ、スコープが切れると自動的にDisposeされるような使い方もできるらしいです。詳細は不勉強のため、省略させてください。
-
外池さんは、いくらなんでも非常識ではありませんか。
私は、分らないことがあるので、C++について質問する場で、質問しているのであって、雑談している訳ではありません。
事務局には報告しましたが、スレッドを荒らされるのは、はっきり言って迷惑です。
ご自身が雑談したり、他人に悪意を投げつけたいなら、そのための掲示板がいくらでもあるはずです。
そもそも、回答者として登場しながら、途中で話についていけなくなって、逆に質問者に質問するというのは、
あまりにお粗末ではありませんか。
ピントのずれたアップをする前に、もう少しC++を勉強なさったらいかがでしょうか。
いいかげんにしてもらえませんか。
-
Azuleanさん、いつもお世話になります。
addressBooks をポインタと考えれば、なんとなく理解の範囲に入ってきたなぁ、という感じはします。
しかし、依然として private でなければいけない理由というのは、ナゾのままです。
> public: private: protected:はC++の参考書なら必ず触れていると思うのですが。
はあ、もちろん項目はあって、索引にも載っています。
C++の本に、CLIのことが載っていないことも理解しています。
蒼の洞窟さんからご提示頂いた宣言を念頭に調べたのですが、どれもたいしたことは書いてありませんでした。
> #C++/CLIでGUIを組むのは苦痛です。(VBやC#に対するメリットが薄い)
自分で、CLRに触ってみて、いろいろ感じることはあります。
批判の嵐を恐れずにいえば、C++でばりばりコーディングしている人が、本気でCLRを受け入れるのかなぁ、という気はします。
ただ、一方でC++が「凋落」しつつあるのも厳然たる事実だと思います。
私は、いずれにせよ、もう少しCLRを勉強してみます。
-
初々心者 さんからの引用 そもそも、回答者として登場しながら、途中で話についていけなくなって、逆に質問者に質問するというのは、
あまりにお粗末ではありませんか。
質問者の状況を把握するために質問する、質問者の理解・考えを確かめる意味で質問すること自体はあり得ると考えます。
初々心者 さんからの引用 ピントのずれたアップをする前に、もう少しC++を勉強なさったらいかがでしょうか。
間違った内容のレスポンスをすることはあり得ます。
それを間違いだと第三者の方に指摘・フォローしてもらえることがありますし、間違ったレスポンスをした人も認識を正す機会を得られることもあります。
そういったやりとりが生まれるのもコミュニティの魅力の一つだと思います。
C++やC++/CLIに関して間違いのないレスポンスしかしてはならないようなことを言われるのであれば、私はレスポンスを控えます。
初々心者 さんからの引用 ただ、一方でC++が「凋落」しつつあるのも厳然たる事実だと思います。
以前のスレッドでもお聞きしました「C++の凋落」という主張ですが、掲載されているサイトを教えていただけませんか?
個人的には「C++の凋落」に対する回答が「C++/CLIを使うこと」にはならないと考えていますが、元の主張内容と照らし合わせない限り、言い切れませんので。
初々心者 さんからの引用 addressBooks をポインタと考えれば、なんとなく理解の範囲に入ってきたなぁ、という感じはします。
しかし、依然として private でなければいけない理由というのは、ナゾのままです。
・Form1クラスはpublicクラスであるため、他のアセンブリ(DLL,exe)からも参照できる。
・AddressBookクラスはアクセスレベルの指定がされていないのでinternal扱いとなり、他のアセンブリから参照できない。
・Form1クラスのpublicなメンバーにAddressBookクラスのインスタンスが含まれている。
(publicクラスのpublicなメンバーは他のアセンブリから参照できる)
・AddressBookクラスは他のアセンブリへの公開ができないのに、Form1クラスでは他のアセンブリへの公開を行っているのでエラーになる。
メンバーの宣言位置、その位置でのアクセスレベルは重要な意味を持ちます。
「どこでも良い」なんてことはありません。
#「どこでも良い」とするなら、ちゃんとpublic: protected: private:等をつけましょうということになります。
そういえば、先のレスポンスで書籍の紹介をさせて頂きましたが、確認されましたか?
-
外池です。
非常に強い口調でお話していることは、かなり非常識だったかな、と反省しており、「試す」ことをしたことも、お詫び申し上げているところです。
一方で、初々者さんの質問に対して、質問を返しているのは、荒らすことが意図では、まったくありません。
初々心者さんが、わかっているとご自身で思っていることとで、周りから見て「いや、わかってないんじゃないか?」と思うことが、あまりにも多いのです。こういうところは、逆に質問しかえさなければ、まったく明らかになりません。
#ピントがずれているって・・・、C++の配列と、CLRのarrayの違いを明確にしたつもりだけれども、
#これ、初々心者さんのAddressBookって何? の答えになってませんかね?
「いいかげんにしえもらえませんか?」に対しては、わかりました。やめましょう。初々者さんのご質問に対しては、一切、お答えしないようにします。
-
#後れ馳せ乍らの感、有り。……
> しかし、依然として private でなければいけない理由というのは、ナゾのままです。
これについては Azulean さんの仰るとおりであります。
なお、参照型とスタックの関係については、2年前のスレッドですが、
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=395212&SiteID=7
ここをご覧いただければ。「見かけ上」スタックに生成するという話です。あと、使用言語について個人的な話をさせていただくと、
私は VB を中心にしています。もちろん C++/CLI も使っていますが、
フレームワークを使って同じ事をするなら、VB の方が速く作れるので。
でも Win32 や COM などのお世話になる部分では、明らかに C++/CLI のほうが良いです。
例のスタックの話も、C++/CLI の専売特許です。
結局、餅は餅屋という事です。でもほんとに、.NET が出てきてから、
異なる言語でソフトウェアを構築するのが楽になったと思います。 -
こんにちは、フォーラム オペレータ大久保です。
初々心者 さんからの引用 そもそも、回答者として登場しながら、途中で話についていけなくなって、逆に質問者に質問するというのは、
あまりにお粗末ではありませんか。
初々心者さん、それは違います。
外池さんは、途中で話しについていけなくなったから質問したのではありません。
初々心者さんの理解度をより深めたいと思ったから、そのために初々心者さんの理解度を確認する必要があったから、あえてあのような形で「質問」をしてくださったのです。
また、初々心者さんは「質問者」と「回答者」を明確に分けて取り扱いたいようですが、私はこのようなインターネットコミュニティで「質問者」「回答者」と身分付けのようなことをするのが嫌いです。
すべての投稿者は「参加者」であり(もちろんマイクロソフト社員も一参加者として参加をしています)、回答者だから間違えるのはおかしいとか、質問者はへりくだるべきとか、そういった考え方は初々心者さん風に言うと「お粗末」だと思っています。
初々心者 さんからの引用 ピントのずれたアップをする前に、もう少しC++を勉強なさったらいかがでしょうか。
いいかげんにしてもらえませんか。
外池さんや他の参加者の皆様のご好意を理解できず(初々心者さんには申し訳ありませんが、あえてこう申し上げます)、このような投稿をされるのであれば、私は初々心者さんの投稿を削除せざるを得ません。
どうか、ご自身の理解度をさらに深めることができるよう、他の参加者の皆様のご意見に耳を傾けてくださいませんか?
Azulean さんが 16 2 2008, 7:59 午前 に投稿してくださったご意見に、私も同意です。
このスレッドに参加してくださった皆様にお礼を申し上げます。
今後ともどうぞよろしくお願いいたします。
-
もう、このスレッドにはアップしないつもりだったのですが、
まず、Abstract さん、ありがとうございます。
いろいろな事柄について、たびたび親切なアドバイスを頂いたことを、深く感謝しています。
説明が不十分だったかもしれませんが、私の第一の目的が、「CLRを勉強する」ことではなく、
「まずCLRとは何者であるかを、見知る」ということでした。
「勉強するか否か」は、それからの問題です。
そうした意味で、強引だったかもしれませんし、奇異に感じたかもしれません。
ただ、そうしたことはともかく、Abstract さんには、深く感謝しています。
大久保さん
別にスレッド自体を削除して頂いて、かまいませんよ。
削除するかどうかの判断は、大久保さんの権利です。
ただし、同じように、どんな回答が私の参考になり、どんな回答者の方に返事をし、どんな回答者の方に
感謝するかは、私の判断で、私の権利です。
別に、私にとって参考にならない回答に対して、私が回答しなかったからといって、責められるものではありません。
回答しなかったことが「気に食わない」からといって、回答者が「捨て台詞」を言っていいということにはなりません。
もちろん無視すればいいだけのことですが、あまりに執拗なので、私も感情的になったかもしれません。
大久保さんご自身が、「初心者に教えてやっているんだ」という、高いところから見下ろす意識を持ってはいませんか。
あるいは、「ここはある程度以上のレベルの人間だけが来るところだ」という意識を持っていませんか。」
なんにせよ、削除するのは、大久保さんの権利ですから、どうぞ削除してください。
時々、マイクロソフトからアンケートが来ますから、その時に改めて私の意見をいわせてもらいます。
-
こんにちは
初々心者さんからすると、「ではフォーラムとはどういう場所なのか ?」という疑問が出てくるかもしれませんので、少々補足します。
フォーラムは”質問”に対して”回答”をもらうための場所として提供しているのではなく、”ディスカッション”や”コミュニケーション”を主体とした、意見交換の場所として提供しています。 そのため、基本的な書き込みのスタンスは、”私はこう思う” や ”私はこう考える” という事になります。
つまり、”回答”と思える内容も、書き込んだ人の、”私はこう思うよ、こすうればよいのでは?” という内容が投稿されていると考えればわかり易いでしょう。 同じトピックであれば、もちろん便乗質問も OK ですし、間違えることもあります。
スレッドを荒らすというのは、極端な例で言えば、広告宣伝だけであったり、まったく違う内容であった場合には、適宜削除や、フォーラム移動を行ったり、その勧告を行いますので、スレッドが続いているという事はそうではないと思っていただければ OK です。
P.S
ここに書き込みを行ってくださる方々は本職は別途あるのに、自らの時間を割いてボランティアで書き込みをしてくださってるはずです。 そのおかげで、毎日のようにMSDN フォーラムが盛りあがりを見せており、感謝しております!
今後ともよろしくお願いいたします。 -
鹿島さん、はじめまして。
フォーラムの趣旨は、理解しました。
しかし、依然として、私が誰かのアップに対して、なぜ、貴社のスタッフの方から、返答を強要されるのか、理解できません。
しかも、「削除せざるをえません」などと、威嚇まがいのことを言われなければならないのか、理解できません。
実際のところ、スレッド自体を削除して頂いてかまいませんよ。
そもそも、私が最初にここへ来たのは、.NET2005とVISTAの組み合わせで不具合が出た時に、貴社に問い合わせて、
ここで質問するように言われたからです。
私の勝手な思い込みで来た訳ではありません。
なにかを誰かに教わって、それに感謝するというのは、人間関係の問題です。
教わることがあれば自然に立場は弱くなるし、自分より知識のある人に対する敬意も生じます。
実際のところ、下世話な言い方で、一度でもなにかを教われば、「少々風を吹かされても仕方ない」みたいなところはあります。
しかし、自分の知識をひけらかすだけで、知りたいことは一度として教えないような人に対してまで、敬意を表しないといけない理由は、少なくとも私には理解できません。
しかも、返答を貴社の方に強要されなければいけないのか、私には理解できません。
私も感情的になったかもしれませんが、根本的なところで、なにか勘違いしていませんか。
-
初々心者さん、早速の返信ありがとうございます。
このまま続けるとフォーラムの趣旨や本スレッドの内容からはずれてしまい、 社員自身がスレ荒らしとなる可能性があるため、下記に別スレッドを用意しました(すいません。フォーラムのシステムの関係で、スレッドの途中から別のフォーラムに移動という事ができないのです)。 引き続き見ていただくかどうか、書き込みいただくかどうかは皆様方の自由です。
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2861815&SiteID=7