2

この質問はすでにここで(実際には2回以上)尋ねられていますが、私自身は投稿から問題の解決策を導き出すことができませんでした。

私が持っているのは、とりわけ、その中に名前が付けられたクラスを備えたライブラリAです。クラスAからにアクセスする必要がありますがstd::map<>、プライベートです。また、私が言及した投稿で見つけた可能性に基づいて、クラスAにはテンプレート化された関数がありません。

私は実際にライブラリを再コンパイルできるので、可視性を簡単に変更できます。ただし、これは大変な作業になります。可視性を変更しても、他に何もクラッシュしないかどうかはわかりません。

私がやりたいのは、クラスでB

// NOT MY CODE -- library <a.h>
class A {
private:
    std::map<int, int> A_map;
};

// MY CODE -- module "b.h"
# include <a.h>
class B : private A {
public:
    B() {
        for (auto it(A_map.begin()); it != A_map.end(); ++it) {
            ...;
        }
    }
};

元のクラスを変更せずに、また、オーバーロード/特殊化するための基本クラスで使用可能なテンプレートメソッドを使用せずに、どうすればよいですか?

4

4 に答える 4

3

最初に、実行しようとしていることが実際に有効であることを非常に確信している必要があります...変数がプライベートであるのにはおそらく正当な理由があります。これを変更すると、Aのインスタンスの状態が破損する可能性があり、カプセル化を解除して読み取るときに、プライベート変数が論理状態または一貫性のある状態になる保証はありません。

その警告がありますが、ライブラリを変更/再コンパイルして、クラスを宣言することができれば、Aの友達がおそらく行く方法です。Bに構成によってAのインスタンスを保持させます。これは友人であるため、Aインスタンスのプライベートメンバーにアクセスできます。


そして、私は特に悪を感じているので、Aを変更せずにカプセル化を破る方法のデモがあります。移植性はありませんが(64ビットLinuxのg ++​​で作業しています)、メモリ内のオブジェクトレイアウトを理解する必要があります。わかりやすくするために、マップをベクトルに変更しました。

#include<vector>
#include<iostream>

class A {
private:
    int blah; //Just to make it a bit more realistic.
    std::vector<int> A_vec;
public:
    void outputVec() {
       std::vector<int>::iterator it = A_vec.begin();
       while(it != A_vec.end()) {
         std::cout << *it << std::endl;
         ++it;
        }
    }
};


int main() {
  A* a = new A();
  std::vector<int>* v = (std::vector<int>*)(((char*)a)+sizeof(long));
  v->push_back(27);
  v->push_back(12);
  a->outputVec();
  return 0;
}
于 2013-02-26T22:42:51.180 に答える
2

プライベート変数は、外部からのアクセスから意図的に保護されています。所有しているクラスが制限の少ないアクセスまたは友達を作ることでメンバーにアクセスできる場合にのみ、メンバーにアクセスできます。

可視性を変更しても他に何もクラッシュしないかどうかはわかりません。

C ++のアクセス制限は、名前の検索を行うときにアクセシビリティが最後にチェックされるように意図的に設計されています。つまり、動作中のプログラムがあり、何かをよりアクセシブルにした場合、アクセシビリティをチェックする前に他のすべての潜在的な問題がすでにチェックされているため、プログラムの動作はまったく変わらないはずです。

于 2013-02-26T22:38:48.027 に答える
1

まず、すべてのデータメンバーを非公開にしておくことをお勧めします。派生クラスが本当ににアクセスする必要がA_mapある場合、最善の方法は、基本クラスにconst参照を返すゲッターを与えることです(読み取りアクセスのみが必要であると想定)。への書き込みアクセスが必要な場合A_mapは、デザインを再考する必要があることを示しています。

それ以外に、C++の規則と規則を真剣に曲げずにクラスへのBアクセスを許可する方法はありません。A_map

ちなみに、私的継承とは別の意味です。これは、クラスのすべてのパブリックメソッドがクラスのAプライベートメソッドになることを意味しますB。言い換えると、プライベート継承とは、の実装を継承するがA、そのインターフェイスは継承しないことを意味します。したがって、ここでは役に立ちません。

于 2013-02-26T22:35:55.400 に答える
0

プライベート継承は、実際には変装した構成です。それは実際には「の観点から実装された」という意味です。

それはさておき、プライベート/パブリック/プロテクトモードの継承に関係なく、プライベートメンバーはプライベートのままになります(派生メンバーからでも、そのクラスの外部からはアクセスできません)。

任意のクラスのプライベートメンバーにアクセスするには、2つの正当な方法があります。

1)Get / Setメソッドを使用してプライベートメンバーにアクセスします(クラスがそれを公開していると仮定します)。

2)クラスと仲良くなります。

あなたの場合、クラスAは図書館に属しています。外部の世界がクラスAと対話するための適切なインターフェイスを提供するのは、図書館ベンダーの責任です。おそらく、図書館ベンダーと話し合う方がよいでしょう。私には、実装の問題というよりは、設計の問題のように見えます。

テストのためだけに、簡単なハックとして、友好的なメカニズムを提案します。

    class A {
      friend class B;
      private:
      std::map<int, int> A_map;
    };

    // MY CODE -- module "b.h"
    class B {
     public:
     B() {
      for (std::map<int, int>::iterator  it(a.A_map.begin()); 
          it != a.A_map.end(); ++it) {  }
     }
     A a;
    };
于 2013-02-27T05:25:06.480 に答える