9

クラスのプライベートメンバーにアクセスするには、クラスをvoidポインターにキャストしてから、構造体にキャストするのが適切ですか?

アクセスする必要のあるデータメンバーを含むクラスを変更する権限がないと思います。倫理的でない場合、間接的な方法でデータメンバーにアクセスするリスクを冒したくありません。

編集:これをさらに編集する必要がありました...クラスは変更されないだろうと確信しているので、その程度は問題ありません...私の唯一の懸念は、そのクラスをコーディングした人がこれを知った場合、彼とうまくいかないかもしれません:(。

4

12 に答える 12

28

ちょっと倫理を考えないようにしましょう。基準を考えてみましょう。

あなたがやろうとしていることは非標準です。セクション 9.2、標準の 12 節を参照してください。「アクセス指定子で区切られた非静的メンバーの割り当て順序は指定されていません。」したがって、プライベート メンバーを含むクラスと、プライベート メンバーを含まない構造体がある場合、標準では、メンバーが同じ順序になることは保証されません。

したがって、あなたのハックが機能する場合、それは偶然にのみ機能し、コンパイラの作成者がたまたまそのように機能しただけです。別のコンパイラ、同じコンパイラの新しいバージョン、または異なるクラス レイアウトで動作するという保証はありません。

言うまでもなく、クラスを変更する (たとえば、単純なアクセサー関数を提供する) 権限がない場合は、クラスの実装の詳細が変更された場合に異議を申し立てる権限がない可能性があります。(パブリックとプライベートの背後にある考え方の 1 つは、約束されているものと自由に変更できるものを区別することです。) したがって、レイアウトが変更されるか、メンバーが別の意味になるか、または完全に削除される可能性があります。

Herb Sutter は、この問題について Guru of the Weekコラムを書きました。

ああ、倫理に関する限り?本当に、本当にこのようなことをしなければならず、それから抜け出せない場合は、非常に注意深く文書化してください。コーディング標準に、標準外の動作にフラグを付けるための何らかの手順がある場合は、それを使用してください。そうでない場合は、何か問題が発生したときに見落とされないように注意してメモしてください。

于 2009-04-07T15:20:12.093 に答える
25

「倫理」が本当に入ってくるかどうかはわかりません。しかし、それはカプセル化から一体を破壊します。

編集:コードレビューを実行している場合、これを受け入れることはほとんどありません。これの必要性を中心に設計する方法がないことを私に納得させるために、あなたは本当に一生懸命働かなければならないでしょう。成功する可能性はありますが、いたるところに大きな警告があり、何かが変わってそれを壊した場合にすぐにわかるように、ハードユニットテストを行う必要があります。

于 2009-04-07T14:44:58.527 に答える
18

完全に準拠した方法でそれを行う方法を示すエントリをブログに追加しました。次のクラスでの使用方法の例を次に示します。

struct A {
private:
  int member;
};

次の例に示すように、タグ名を宣言し、robber をインスタンス化するだけです (私の投稿では、robber の実装を示しています)。その後、メンバー ポインターを使用してそのメンバーにアクセスできます。

struct Amem { typedef int type; };
template class rob<Amem, &A::member>;

int main() {
  A a;
  a.*result<Amem>::ptr = 42; // Doh!
}

しかし実際には、これは c++ のアクセス ルールが信頼できないことを示しているわけではありません。言語規則は、偶発的な間違いから保護するように設計されています。オブジェクトのデータを盗もうとしても、言語の設計により、阻止するのに長い道のりはかかりません。


上記は、準拠した方法でプライベートおよび保護されたメンバーにアクセスする方法です。これは、標準に準拠した方法で保護されたメンバーにアクセスする別の方法です。基本的な考え方は、メンバーポインターを使用することです

std::deque<int> &getAdapted(std::stack<int> &s) {
    struct voyeur : stack<int> 
    { using stack<int>::c; };
    return s.*(&voyeur::c);
}

int main() {
    std::stack<int> s;
    std::deque<int> &adapted = getAdapted(s);
    output(adapted); // print the stack...
}

キャストやタイプのパニングは含まれていません。std::stack<int>メンバー名がパブリックなクラスから派生したクラスを介して、保護されたメンバーへのポインターを取得するため、コンパイラーはこれを許可します。次に、std::stack<int>オブジェクトでそれを使用しますが、これも許可されています。

于 2009-06-25T14:59:46.423 に答える
8

古いバージョンのアプリケーションではヘッダー ファイルに変更を加えることがほとんど不可能な、非常にくだらないソース管理システムが導入されていたので、私はこれに遭遇しました。

場合によっては、ハックする必要があります。

プライベート データ メンバーにアクセスする必要があるソース ファイルでは、最初の行として次のように記述できます。

#define private public
#define protected public

必要なものにアクセスできます。

于 2009-04-07T15:32:24.247 に答える
7

いいえ、あなたがしているのは純粋な悪です。

于 2009-04-07T14:46:34.903 に答える
5

"絶対とは絶対言うな"。きっと宇宙のどこかに、そうせざるを得ない事態が…。

しかし、私がそれをしなければならなかった場合、私は確かにうんざりするでしょう. 引き金を引く前に、状況について多くの意見を得る必要があります。あなたの特定の状況について説明していただけますか?

コメント/質問への回答 -- 「許可」の定義 -- 機関の許可? それはプログラミングの問題ではないように思えますが、その許可を主張している人に話しかける必要があります。多分これは技術的な問題というよりは政治的な問題でしょうか? 繰り返しになりますが、状況の政治的な問題が多少あったとしても、もっと具体的な情報が必要だと思います。ただし、それはウェブサイトの範囲外と見なされる場合とされない場合があります。

于 2009-04-07T14:47:21.220 に答える
4

これを行いたい場合は、キャストを忘れてください。ヘッダー ファイルのクラス宣言を変更するだけです。

class A {
  private:
    int x;
};

それを次のように変更します。

class A {
  public:
    int x;
};

そして、あなたは行ってもいいです。うーん、「良い」という言葉は適切ではないかもしれません。

于 2009-04-07T14:47:35.760 に答える
3

それは倫理的ですが、通常、未定義の動作と移植性に隣接する多くの汚いコードです。絶対に必要な場合にのみ実行してください。

于 2009-04-07T14:46:18.947 に答える
2

ああ、抽象化 - あなたはそれなしでは生きられませんが、それでも時々対処するのはとても苦痛です:)

とにかく、倫理はさておき、クラスの「所有者」が内部実装を変更することを決定した場合、または単にプライベートデータメンバーの順序を逆にした場合はどうなりますか?

于 2009-04-07T14:51:29.167 に答える
1

唯一の「倫理的」問題は、あなたのコードを理解して維持しなければならない貧しい野郎にあなたが何をしているのかです。

プライベートメンバーはまさにそれです。彼はいつの日かそのメンバーを変更する可能性があり、おそらくそうするでしょう。それが起こったとき、あなたが期待していたメンバーではなく、メモリがまだそこにある可能性が高いため、気付かないかもしれません. コードが実行されたときに、想像できるほぼ不可能なことのほとんどが起こり始める可能性があります。どうすればそれをデバッグできるようになるのでしょうか?

于 2009-04-07T17:59:47.107 に答える
0

簡単な答え: いいえ。

これは倫理的ではなく、ある時点でメンテナンスの悪夢に変わります。ライブラリの内部プライベート メンバーは、コードを変更して壊す可能性があります。ライブラリの開発者は、カプセル化に違反していることを知る必要はありません (また、知りたくもありません)。

クラスには通常、メソッドに関する不変条件があり、ドキュメント化されない場合もありますが、外部から値にアクセスして変更すると、これらの不変条件が壊れる可能性があります。例として、ベクター内の予約済みスペースをより高い値に変更すると、ベクターは既存のスペースがいっぱいになるまで新しいスペースを割り当てず、割り当てられていないメモリに到達する前に発生しません。アプリケーションがクラッシュします。

属性が非公開の場合、それを使用するのはあなたのためではなく、クラス自体、またはメンバーについて知っているクラスの友人、その使用方法、それを壊さない方法についてのみ使用できます。プログラマーがフィールドを変更することを望んでいた場合、それは public になります。

于 2009-04-07T14:51:47.137 に答える
-1

このクラスは、あなたが取り組んでいるプロジェクトの一部であると思います。

ここで倫理的な問題が 1 つあります。会社でコードの所有権を仙骨と見なしている場合です。または、最悪の場合、自分のものではないコードを変更することは許可されません。はい その階級を維持している人の気持ちを傷つけるかもしれません。または、彼の給与が彼のコードに関連している場合、彼を怒らせます。ですから、彼に助けを求めるのが最善であり、いくつかの提案があります。ゲッター関数を追加するか、プライベートをパブリックに変更します-すべてその新しいコードを使用する直感に基づいています。

あなたが言及したハックは、実際にはベッドの練習です。そのコードを変更できない場合、メンテナーは何も変更しません。アダプター設計パターンの使用を検討してください。

于 2009-11-28T17:32:38.363 に答える