0

静的メンバーの継承と C++ での保護について質問があります。心の状態を書くのは必ずしも簡単ではないので、十分に明確になることを願っています:)カスタムフォーマットでテキストファイルをロードするグラフィカルプログラム用の単純な(テキストパーサー)を書いています。現在、テキスト部分はほぼ完成しており、ここで、ファイルからロードしたデータをオブジェクトに供給するために、いくつかのオブジェクトを生成する必要があります。

この質問は、C ++の時間1に属していると思いますが、立ち往生しています。たとえば、テキスト ファイルからロードしたのは、LAYER と PLINE の 2 種類の論理「ノード」だけです。これらには、両方に共通する属性と共通しない属性もあります。LAYER と PLINE との関係は今ではまったく関係ありません。私を悩ませているのは、両方の属性を接続して処理する方法です。

両方の基本クラスとしてDataObjを選択したとします。LAYER と PLINE の両方に名前を付けることができるため、DataObj には「name」というメンバーがあります。LAYER には、レイヤーのみに共通の属性があります。"locked" であり、PLINE には pline にのみ共通の属性があります。"色"。物事を行う「学校のやり方」では、次のようになります。

/// i use const char* for everything to not complicate things ... 
...
class DataObj {
  ...
  const char* name;
  ...
}
...
class Layer : public DataObj {
 ...
 const char* locked;
 ...
}
...
class Pline : public DataObj {
 ...
 const char* color;
 ... 
}
...
int main(){
   Layer* l = new Layer();
   l.name = "first layer";
   l.locked = "false";

   Pline* p = new Pline();
   p.name = "wonderful line";
   p.color = "0xFF3300";
}
...

今は、特にパーサーからのデータをオブジェクトに供給するときに、静的な型付きメンバー名 (および将来的にはそれらのアクセサー) を本当に気にしない方法で、より「動的に」実行したいと考えています。つまり、2 つのノード タイプのみで簡単に実行できますが、数十以上のノード タイプを使用することになります。

したがって、私がやりたい概念は、各ノード タイプ (クラス) に許可された属性のベクトルを「静的に」プッシュし、この属性がオブジェクトで許可されているかどうかをチェックし、解析中に設定することです。おそらく2つの重要なメンバーが必要です1. kvペアのstd::map、2つ目は特定のノードに許可された属性の静的ベクトルです。前に入力したコードに従ってください。

...
class DataObj {
  ...
  static std::vector<const char*> allowedAttrs;
  std::map <const char*, const char*> attrs;

  private: 
     static bool isInit;
  ...
}
...
DataObj::DataObj(){
  if(!isInit)
    allowedAttrs.push_back("name");
  isInit = true;
}
...
Layer::Layer(){
  if(!isInit) // private static for Layer
     allowedAttrs.push_back("locked");
}
...
Pline::Pline(){
  if(!isInit) // private static for Pline
     allowedAttrs.push_back("color");
}
...

私がここで得ている問題は、おそらく月から見えるものです。最初に新しいレイヤーを初期化し、次に新しい Pline を初期化すると、Pline は allowedAttrs ベクトルに名前、ロック、および色を持ちますが、これは正しくありません。「ロック」はレイヤー ノードに対してのみ有効である必要があるためです。

したがって、レイヤーオブジェクトの「locked」などの非一般的な属性に対してメンバー「allowedAttrs」が「プライベート」になるだけでなく、スーパークラス「DataObj」からの「パブリック」の性質を保持する方法で、この問題を解決する方法が必要です-そのため、「名前」などの共有属性をキャッチできます。言い換えれば、基本クラスまでの「継承フロー」を「中断」し、同じコードを何度も繰り返すノードクラス (オブジェクト) ごとに新しい変数を定義したくありません。(仮想変数のようなもの)。

この質問が(それほど)ばかげていないことを願っています。あなたの答えに本当に感謝します。

4

2 に答える 2

3

1) タイプごとに個別の静的メンバーを使用して、タイプごとに許可された属性を保持します。
2)静的メンバーを関数に移動します。これはより安全であり、常に初期化されているかどうかを確認するためのチェックを回避する可能性があります(コンパイラの性能やその他の詳細によって異なります)
3)const char*非常に具体的なものを除いて使用しないでください。それらが何であるかわからない場合は、常に を使用してstd::stringください。この場合、 を使用する必要std::stringがあります。
4)allowedAttrsベクトルからに変更しましたset。属性の数が多いと速くなり、数が少ないと遅くなる可能性があります。

ベースは次のとおりです。

class DataObj {
  const std::set<std::string>& get_allowed_data_attributes() static {    
    static std::set<std::string> allowedAttrs = {"name"};
    return allowedAttrs;
  }
  std::map <std::string, std::string> attrs;
  public:
     DataObj(){ }
     void set_attribute(std::string key, std::string value) {
         auto it = get_allowed_data_attributes().find(key);
         if (it  == get_allowed_data_attributes().end())
            throw bad_key_exception(key);
         attrs.insert(std::make_pair(std::move(key), std::move(value)));
     }
     const std::string& get_attribute(const std::string& key) const {
         auto it = attrs().find(key);
         if (it  == attrs().end())
            throw bad_key_exception(key);
         return it->second;
     }
};

派生したものは次のとおりです。

class Layer : public DataObj {
  const std::set<std::string>& get_allowed_data_attributes() static {    
    static std::set<std::string> allowedAttrs = {"locked"};
    return allowedAttrs;
  }
  public:
     DataObj(){ }
     void set_attribute(std::string key, std::string value) {
         auto it = get_allowed_data_attributes().find(key);
         if (it  == get_allowed_data_attributes().end())
            DataObj::set_attribute(std::move(key), std::move(value));
         else
            attrs.insert(std::make_pair(std::move(key), std::move(value)));
     }
     const std::string& get_attribute(const std::string& key) const {
         auto it = attrs().find(key);
         if (it  == attrs().end())
            return DataObj::get_attribute(key);
         else
            return it->second;
     }
};

bad_key_exception無効なキーを指定すると、追加する必要がある がスローされることに注意してください。から継承していることを確認してくださいstd::runtime_error

于 2012-10-01T21:49:16.097 に答える
2

許可された属性のベクトルを実装する方法を次に示します。各タイプに許可された属性のリストを含め、初期化中に基本クラスのリストをコピーします。

class DataObj {
  ...
  static std::vector<std::string> allowedAttrs;
  std::map <std::string, std::string> attrs;

  private: 
     static bool isInit;
  ...
}
class Layer {
  static std::vector<std::string> allowedAttrs;
  ...
};
class PLine {
  static std::vector<std::string> allowedAttrs;
}
...
DataObj::DataObj(){
  if(!isInit)
    allowedAttrs.push_back("name");
  isInit = true;
}
...
Layer::Layer(){
  if(!isInit) { // private static for Layer
     allowedAttrs = DataObj::allowedAttrs;
     allowedAttrs.push_back("locked");
  }
}
...
Pline::Pline(){
  if(!isInit) { // private static for Pline
     allowedAttrs = DataObj::allowedAttrs;
     allowedAttrs.push_back("color");
  }

}

ノート:

  • ベクトルとマップの両方std::stringではなく、 を使用します。潜在的に役立つ可能性がありますが、 char*これは単なるバグです。vector<char*>map<char*,char*>

  • ルックアップ関数をもう少し賢くすることで、基本クラスのリストの重複を避けることができます。

于 2012-10-01T21:47:21.580 に答える