none
データのサブクラス化 RRS feed

  • 質問

  • .NET2005 VISTA です。

     

    CLRでデータの安全性を保つ方法について質問します。

     

    MFCですと、よくデータをサブクラス化すると思うのです。

     

    ***view.cpp で

    class hoge a[5]; 

     

    ***.h で

    class hoge {
     private:
      char dataMusic;
     public:
      void setdata(CString ss);
      CString getdate();
    };
     extern class hoge a[5];

     

    とするようなやり方です。

     

    CLRの場合は、どのようにコードィングしたらいいのでしょうか。 

     

    過去ログを見ると、グローバル変数の作り方として、

    global というサブクラスを作っておいて、

     

    Code Snippet

    // global.h

    #ifndef GLOBAL_H__
    #define GLOBAL_H__


    ref class Global {
    public:
     static array
    ^ ss;
    private:
     static Global();
    };


    #endif

     

     

    Code Snippet

    // global.cpp

    #include "stdafx.h"
    #include "global.h"

     

    static Global::Global() {
      ss = gcnew array<System::String^,2>{ {"0-0","0-1"}, {"1-0","1-1"},  };
    }

     

     

    というのがありますが、

    サブクラスに置いても、これはスレッドの趣旨どおり外部変数だと思うのです。

     

    要は、private にするかどうか、ということかとも思ったのですが、その場合にデータの出し入れをどうするかということも分りません。

     

    CLRでは、データの安全性を保つ場合、一般的に、どのようにするのでしょうか。

    2008年1月27日 20:50

すべての返信

  • #あまりサブクラス化とは言わないような……

     

    一般的には、プロパティかメソッドでカプセル化します。

    フィールド(つまりメンバ変数)は private にして、これらは public にします。

    問題は、プロパティとメソッドのどちらを使用すべきかと云う点ですが、

    これについては下記ページにガイドラインがありますので、参考にしてください。

    http://msdn2.microsoft.com/ja-jp/library/ms229054(VS.80).aspx

    2008年1月27日 23:05
  •  初々心者 さんからの引用

    MFCですと、よくデータをサブクラス化すると思うのです。

     

    ***view.cpp で

    class hoge a[5]; 

     

    ***.h で

    class hoge {
     private:
      char data;
     public:
      void setdata(CString ss);
      CString getdate();
    };

    これのどこが、「サブクラス化」なのでしょうか?

     

     初々心者 さんからの引用

    CLRでデータの安全性を保つ方法について質問します。

    MFCにしろ、CLRにしろ、そんな目的のためには、「サブクラス化」は使えません。

     

    2008年1月28日 1:22
  • Abstract さん、ありがとうございます。

     

    > 一般的には、プロパティかメソッドでカプセル化します。

    > フィールド(つまりメンバ変数)は private にして、これらは public にします。

     

    正直なところ、この部分からよくわかりません。

    メンバ変数を置く場所は、Form1.h の中なのでしょうか。

     

    たとえば、二次元配列 static array<System:Tongue Tiedtring^,2>^ ss を private にするとして、

    データの出し入れは、どのようにするのでしょうか。

     

    public なら、

    ss = gcnew array<String^, 2>(2, 4){
            {・・・・

     

    というように素直に定義していけばいいと思うのですが。

     

    心苦しいのですが、コードを示して頂けませんでしょうか。

     

    2008年1月28日 4:55
  • 外池と申します。

     

    すいません、議論がすれ違いにならないか、老婆心ながら懸念しています。すれ違いにならないように、変に誤解している(誤解をまねく)用語を用いずに(サブクラスとか、カプセルとか)、平易にやりたいことを説明してください。

     

    1.Windowsアプリだと思いますが、それでよろしいですか?

     

    2.安全な場所に隠しておきたい2次元配列は、

      Formオブジェクトの個々のインスタンスごとに用意すべきものですか?

      それともFormクラスに属するものの、複数のインスタンスから共通にアクセスできることを意図していますか?

      それともFormクラスとは無関係に、プログラムのどこからでも共通にアクセスできることを意図していますか?

     

    3.その上で、改めて、上述の2次元配列は、何からのアクセスに対して、安全に隠しておきたいのですか?

     

    これらの説明がなされていない、つまり、ご質問の背景にある意図が不明なので(誤った用語を用いたら、一層混乱する)、どなたも返答に窮することになろうかと思います。

     

     

    2008年1月28日 5:33
  • Global.h

    public ref class Global
    {
    private:
     static array<String^,2>^ ss;
    private:
     static Global(void);
    public:
     static array<String^,2>^ GetSS(void);
    };

     

     

    Global.cpp

    static Global::Global(void)
    {
     ss = gcnew array<String^,2>{{"0-0","0-1"},{"1-0","1-1"}};
    }

    array<String^,2>^ Global::GetSS(void)
    {
     return ss;
    }

     

     

    とか。

    注:実際には ss をそのまま返すのでなく、複製したものを返すほうが安全です。

    2008年1月28日 5:51
  • ありがとうございます。

     

    ご提示のコードのままで通らなかったので、下記のようにしました。

     

    global.cpp

    #include "stdafx.h"
    #include "global.h"

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    static Global::Global(void)
    {
     ss = gcnew array{{"0-0","0-1"},{"1-0","1-1"}};
    }

    array^ Global::GetSS(void)
    {
     return ss;
    }

     

     

     

    global.h

    #pragma once

    namespace 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;

    public ref class Global
    {
    private:
     static array^ ss;
    private:
     static Global(void);
    public:
     static array^ GetSS(void);
    };
    }

     

     

    これで、まだ、

     

    'Global' : 識別子がクラス名でも名前空間名でもありません。
    型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
    'ss' : 定義されていない識別子です。
    'Global' : 関数に戻り値の型が指定されていません。戻り値を void 型と見なします。
    'Global' : 識別子がクラス名でも名前空間名でもありません。

     

    というエラーになります。

     

     

    やっていて、いくつか疑問が出たのですが、

     

    1.これが、「プロパティまたはメソッドでカプセル化」なのでしょうか。

    2.Form1.hで、配列の値を取得するには、どのようなコードになるのでしょうか。

    3.逆に、private な ss の値を上書きする関数は、どのようなコードになるのでしょうか。

    4.MFCですと、なにをするにもまずサブクラス化してから、みたいなところがありますが、

      そもそもCLRでは、あまりサブクラスは使わないのでしょうか。

    アドバイスを、よろしくお願いいたします。

    2008年1月28日 9:14
  • 2点のみ回答します。

     

     初々心者 さんからの引用

    'Global' : 識別子がクラス名でも名前空間名でもありません。
    型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
    'ss' : 定義されていない識別子です。
    'Global' : 関数に戻り値の型が指定されていません。戻り値を void 型と見なします。
    'Global' : 識別子がクラス名でも名前空間名でもありません。

     

    というエラーになります。

    global.hでは”namespace dataclass { ”の行がありますがglobal.cppにはありません。

    global.cppに”namespace dataclass { ”を追加してみてください。

    (最終行に } を追加するのも忘れずに)

     

     初々心者 さんからの引用

    4.MFCですと、なにをするにもまずサブクラス化してから、みたいなところがありますが、

      そもそもCLRでは、あまりサブクラスは使わないのでしょうか。

    他の方もすでに書かれていますが、初々心者さんは「サブクラス化」という用語を間違って使っています。

    【サブクラス化】

    http://e-words.jp/w/E382B5E38396E382AFE383A9E382B9E58C96.html

    MFCでサブクラス化を行う場合は例えばCButtonクラスを継承して機能追加したボタンクラスを作るなど

    そういった場合に「サブクラス化」すると言います。

    今回の場合は単純にクラスの作り方についての質問かと思います。

    2008年1月28日 11:04
  • Global の完全限定名(つまり本名)が dataclass::Global になっているのでエラーになります。
    だから解決策は、.cpp の方に using namespace dataclass; を追加するか、
    或いは .h の方で namespace dataclass{} を削除するか。

    追記:C.John さんの提示された方法も有効です。

     

    基本的に、外部の名前空間の中で宣言されている型は、
    その型名の前に名前空間名を付けないとアクセスできません。
    だから String だって、System:: String^ としなければ、
    「String はクラスでも名前空間でもない」となるわけです。
    この事は重要ですので、是非覚えてください。

     

    あと疑問についての回答。

     

    1、
    そうですね。「隠蔽する」とも言いますが。

     

    2、
    Form1.h がどんなんであるか、私は知りませんが、
    Global::GetSS();
    これだけ。

     

    3、
    static void SetSS(array<String^,2>^ value)
    {
      ss = value;
    }
    みたいな(未検証)。

     

    4、
    Win32 や MFC でのサブクラス化は、
    CLR においては WndProc をオーバーライドする事を意味します。
    あまり一般的ではありません。

    2008年1月28日 11:08
  • C.John さん、Abstract さん、ありがとうございます。

     

    > 今回の場合は単純にクラスの作り方についての質問かと思います。

     

    クラスには必ず親があると思い、軽い気持ちで 「サブクラス」 という言葉を使ったのですが、

    不適切でした。

    たいへん失礼いたしました。

     

     

    値の出し入れとも、成功しました。

    ありがとうございました。

     

     

    最後に1点、教えてください。

    このコードは、「プロパティのカプセル化」なのでしょうか。

    それとも、「メソッドでカプセル化」なのでしょうか。

    最初に Abstract さんがリンクしてくださったサイトは読んだのですが、、、

    2008年1月28日 20:51
  • アクセスするのにメソッドを使ってるんだから、
    「メソッドで(クラス内の変数を)カプセル化」でしょう。
    #もっとも、今回定義したメソッドは単純すぎて、
    #変数に直接アクセスするのと大差ありません。

     

    ただ最近は、あまりカプセル化という言葉も使わなくなった気がします。
    単純に「○○を返すメソッドを定義した」で良いのでは?

     

    それと、子クラスにすると云う意味での「サブクラス化」も、色々な言い方があります。
    「○○から派生させる」とか「○○を継承する」とか、「○○を拡張する」とか。
    むしろ「サブクラス化」は少数派なんじゃないかな?(紛らわしいし)

    2008年1月28日 23:05
  • 外池です。どうも・・・、

     

    「カプセル化しないといけない」ようだから「カプセル化しよう」、と、用語だけに振り回されているように感じられてなりません。まぁ、今回のご質問が「カプセル化」ということの一般論の勉強なのであればまったく問題なくて、さらに一層いろいろ調べてみられれば結構かと思います。

     

    ただ、今回のコードの実例のやりとりが、何かの実務のために具体的な使われるのであれば、Abstractさんの##マークの2行は是非忘れないでください。変数に直接アクセスすることと実質まったく変わっていない(実質カプセル化になっていない)ので。

     

     

    2008年1月29日 0:03
  • たいへんありがとうございました。

     

    解決しました。

     

    2008年1月29日 6:05