• ベストアンサー

C++のfriend classについて

C++のfriend classについて C++の初心者です。 C++でのfriend classは基本的に、全プロパティに対するsetter,getterを持たせて 集約、コンポジションにより代替が可能だと思うのですが、今勉強の為に読解して いるソースではsetter,getterの実装がなされているクラスの使用に対しても friend 宣言が多発していて中途半端なルールになっていると感じてしまいます。 friend 宣言によって別途実現可能になる事や、パフォーマンス的に有利(微々たる 物なはず)な事ってあるのでしょうか?

  • enrik
  • お礼率42% (3/7)

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

> プロパティに対象のクラスを持っていると、ですよね。 プロパティというのがよくわかりません。 データメンバのことだと思ったのですが、違うのでしょうか? 安易にアクセッサを設けると... class foo {  int value; public:  int getter() const { return value; }  void setter(int x) { value = x; } }; となっていた場合、 int main() {  foo f;  f.setter(123); } のように、外部から好きなようにアクセスできてしまいます。 これに対して、 class foo {  int value; public:  friend class bar; }; class bar { public:  static void func(foo& f)  {   f.value = 123; // OK  } }; int main() {  foo f;  bar::func(f);  f.setter(123); // エラー } 上のようにfriendを使うと、barクラスのメンバ関数からはfooのprivateメンバにアクセスできますが、それ以外からはできなくなります。

enrik
質問者

お礼

>プロパティというのがよくわかりません。 >データメンバのことだと思ったのですが、違うのでしょうか? "プロパティ"はprivateなメンバ変数を指しておりました。 独特な言い回しをしてしまっており、申し訳ございません。 コードのご提示ありがとうございます。 また、ご提示頂いたコードでは、確かにアクセサ関数では 実現不可な事も理解しました。 なんとなくイメージできる様になってきたので、今回のご回答 を参考に考えながら設計してみようと思います。

その他の回答 (3)

回答No.4

補足どもです。 脳内変換で読み替えた日本語があっていれば 1点勘違いしているっぽく見えたのでついでに指摘しておきます。 >C++でのfriend classは基本的に >全プロパティに対するsetter,getterを持たせて集約、コンポジションにより代替が可能だと思う C++でのfriend classは基本的に 全てのメンバ変数ついてsetter,getterを持たせることによって 集約、コンポジションの代替が可能だと思う ↑の日本語意味が同じだとすれば、 どちらかといえば逆です。 friendは、 コンポジット等のパターンによって集約されたクラスから メンバアクセスするために使うんじゃなくて 現在のインターフェイスを拡張するデコレーター等のパターンにて 作成したクラスがprivateメンバにアクセスするために 使用する形が一般的と思います。

enrik
質問者

お礼

あ、リンクが逆でした。 正しくは下記です。 >プロパティ http://e-words.jp/w/E38397E383ADE38391E38386E382A3.html >コンポジット 集約 http://iwatam-server.sakura.ne.jp/software/devintro/classdiag/classdiag/x231.html

enrik
質問者

補足

揚げ足っぽくなり、大変申し訳ないのですが、文化により 意味する内容が違う事が良くあるので、意図的に一般的だ と思う単語を選んでいました。 それぞれ下記と同意に使っています。 >コンポジット 集約 http://e-words.jp/w/E38397E383ADE38391E38386E382A3.html >プロパティ http://iwatam-server.sakura.ne.jp/software/devintro/classdiag/classdiag/x231.html ですので、コンポジットパターンが出てくる時点で、うっすらと 認識はずれています。

回答No.3

プロパティ は、 getter/setterの 総称みたいなもので変数のように扱える関数ですよね? # VBとか C#にあるような。 んーと、日本語がぐだぐだで、質問がなにをいっているのかぜんぜん理解できないのですが、 とりあえず、参考にしているソースコードは参考にしてはいけないような気がします。 friendの使い方としては、#2 で説明されているとおり、通常公開していないインターフェイスを ある特定のクラスや関数にだけは、公開するといった使い方をします。 たとえば、 クラス単位でfriendに宣言するのなら、 きっとそのクラスは、fiend宣言しているクラスの内部処理をまかなうことが多いのではないでしょうかね。 # 公開されていないインターフェイス部分の代替機能 といっても、ちゃんとしたクラス設計ができていれば、friendを使用することはほとんどないです。 だって公開してないインタフェースなら公開していないそれなりの理由がありますから。 もし、機能拡張で元のクラスをいじりたくないだけという場合もあるかもしれませんが その場合、隠蔽を無意味にしてしまうのでカプセル化が崩壊しはじめると考えるべきです。 ながくなりましたが、最後にもうちょっとだけ。 メンバ変数の変更を公開するということは、 変更するという行為には何らかの目的があるはずですので メンバ関数は、目的に則した名前をつけてあげましょう。 また、C++では 基本的に getterやsetterという考え方はしない方がよいです。 基本的にメンバ変数の数も必要最小限してあげた方がモジュール強度があがり便利です。 クラスには状態を記憶するメンバ変数だけにして、データ部分は関数の引数で持ってくるのがよいと思います。 # 状態を記憶しているので単純な取得/設定に意味がないともいう。 データ部分を包括したクラスではデータ部分がメンバに含まれてしまうのは仕方ないですけど。。。 クラス設計になれてきて、処理とデータと操作を別々の機能として役割分担できるようになれば 自然と理解できるようになると思います。

enrik
質問者

お礼

"お礼"で入力すべきだったのですが、"補足"として入力して しまいました。 改めてまして、ご回答有難うございました。

enrik
質問者

補足

>んーと、日本語がぐだぐだで、質問がなにをいっているのか >ぜんぜん理解できないのですが、 質問としては下記になります。 >>friend 宣言によって別途実現可能になる事や、パフォーマンス的 >>に有利(微々たる物なはず)な事ってあるのでしょうか? ↑の"別途実現可能"とは下記を意味します。 >>全プロパティに対するsetter,getterを持たせて >>集約、コンポジションにより代替が可能だと思う 説明不足で大変申し訳ない箇所なのですが、"プロパティ" はprivateなメンバ変数を指します。 文化的にこの呼び名になれてしまっていたので、 使っていました。 以降、使わない様に気をつけます。 >とりあえず、参考にしているソースコードは参考にしてはいけない >ような気がします。 今はその通りだと判断しています。 まさにカプセル化が崩壊しているコードを見ています。 その他の意見も、ありがとうございます。 C++を勉強する上で、大変参考になりました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

setterやgetterを持たせてしまうと、どこからでもアクセスできてしまいます。 一方で、friendを使うと、指定したクラスや関数からしかアクセスできません。 ですので、friendは、本来であればメンバ関数にすべきなのだけれども、文法上、メンバ関数にできないか、メンバ関数にせずに外付けの関数やクラスにした方が大きなメリットがある場合に使うべきものです。

enrik
質問者

補足

>setterやgetterを持たせてしまうと、どこからでもアクセスできてしまいます。 プロパティに対象のクラスを持っていると、ですよね。 だとすると、やはり friend はこれと等価であると思います。 何か間違っているでしょうか・・??

関連するQ&A

  • 【C++】相互参照

    以下のような相互参照は、 感覚的には、なるべくならしない方が良いと感じるのですが、 どのようなメリット・デメリットがあるでしょうか? class A B* m_b class B A* m_a ■少なくとも、多くのクラスによって構成された巨大なDLLが、  相互参照ばかりで作られると、  (1)クラスAのポインタ型のメンバーが、クラスB内で値が変わりうる、   また、クラスBを、クラスCで参照していたら、そこでも値が変わりうる。   さらにクラスCを、クラスDで参照していたら、(略)となり、   処理・メンバー値の変更の影響の把握が困難になる。  (2)lib/objの作成順のミスや管理、  (3)いずれかのクラスのリコンパイルが発生した時、   リリース物のリコンパイルが発生しまくる。  ということがあり、良くないと考えています。 - - - - - - - - - - - - - - - 相互にインタフェースし合う項目を、メンバーとして宣言しつつ、 そのGetter、Setterを用意すれば、強結合にせずに作れるという認識ですが合っていますか? class A B* m_b int x1、y1、z1   x1、y1、z1のGetter、Setter class B Privateなメンバーx、y、z int x2、y2、z2   x2、y2、z2のGetter、Setter .

  • フレンド宣言のスコープがわかりません。

    フレンド宣言のスコープがわかりません。 #include <iostream> class X { friend class Y; friend void f() { std::cout << "f()" << std::endl; } }; //class Y; //void f(); class Z { Y *ymem; void g() { ::f(); } }; int main() { ::f(); return 0; } C++プライマー第4版を読んでいます。511ページに上記のプログラムがあり、 「フレンドで導入されたクラスと関数(定義または宣言)は、すでに宣言されたものとして使うことができる。」 と説明されています。 しかし、g++(gcc4.4.1)でコンパイルするとエラーになります。コメント部分を外すと実行できます。 C++プライマーが正しいのか、gccが正しいのか、私が思い違いをしているのか、わかりません。 ご存知の方はいませんか。

  • スーパークラスのインスタンスをサブクラスにアップキャスト

    ↑したい場合はどうしたらいいでしょうか。 データ構造体(beans)なのでスーパークラスのgetterとsetterを 利用してサブクラスに再構築する方法が考えられますが どうも腑に落ちないので質問してみました。 サブクラス側で継承をやめて集約にするにしても getterとsetterをまた書くの?って感じでわずらわしいです。 (jsp:getPropertyを利用するかもしれませんしね) さらにスーパークラスのメソッド全てをインタフェース化してサブクラスで実装とかしてたら具合が悪くなってきます。 この長年の疑問に終止符を打ってくれる方はいませんか?

    • ベストアンサー
    • Java
  • C++でfriendクラスにしているのにprivateメンバにアクセスできない

    C++でメンバ変数をprivateにして、特定のクラスにだけ公開するようにクラスをfriend指定したのですがprivateメンバにアクセスできませんとエラーが吐かれてしまいます。 先行宣言したりもしてみたのですがどうしても使用できません。 何か心当たりのあるかた教えてください。 class A { friend class B; private: int a; }; class B { public: void test( A *a ) { a->a = 0; } }; コードは違いますがこんな感じのことをしたいのです。 /* コンソールで小さなプログラムでテストしてみると動くのにいざ実際のソースに組み込むと動かないという奇妙な状態です。よろしくお願いします。 */

  • C++ のクラスの定義

    C++の初心者です。 C++のことでお聞きしたいことがあります。 namespace test1{ class A { friend class B; protected: int a; }; } とtest1の下にAクラスを作り namespace test2{ class B { public: test1::A A1; }; } と別のnamespaceにBというクラスを作り、 A1というAのインスタンスを持ちたいのです。 しかし、Aというクラスを先に宣言しているので Bというクラスが解らないらしく friendがうまく働きません。 friend class test2::B としても test2がまだ宣言されていないので、 ????とコンパイルエラーが出ます。 先にtest2::B を宣言してしまうと、 今度はtest1::Aが解らずに エラーが出てしまいます。 こんな場合はどのように書けばよろしいのでしょうか? 環境はwindows2000でVC++ 6.0です。 どうか宜しくお願いいたします。

  • アノテーションを利用したアクセサメソッドの自動定義というのは実現可能?

    近年、デフォルトコンストラクタと各フィールドに対するアクセサメソッド(setter/getter)を備えたJavaBeansが話題になっていると思います。例えばこんなクラス。 class TestBeans {  private int number;  public void setNumber(int number) {   this.number = number;  }  public int getNumber() {   return number;  } } しかし、フィールドの数が増えてくると、コードがどんどん冗長になってくると思います。 そこで、ふと思ったのですが、リフレクションとJDK5のアノテーションを使って、下記のようにスッキリとアクセサメソッドが利用できるようになったりしないかなぁ、と。 class TestBeans {  @Getter @Setter  private int number; } こうすることによって、getNumber / setNumber が利用できるようになったりしないかな、ということです。 アノテーションの自作やリフレクションに関する知識が乏しいので、私にはよくわかりませんでした。 こういったことは実現可能なのでしょうか? また可能ならばどのように実装するのでしょうか? よろしくお願いいたします。

    • ベストアンサー
    • Java
  • C++ の フレンドクラスについての疑問

    vc++でプログラムを作っています。 クラスのアクセス制限の部分で疑問が出てきたので、ソースとその疑問について 下記に示しています。 const int CAMERA_NUMBER = 0 class CalculateMatrix{ public: □static bool computeFundamentalMatrix( const cv::Mat P1 , const cv::Mat P2 , const cv::Mat T1 , const cv::Mat T2 , cv::Mat &F ); }; class ReferenceCameras{ □friend class CalculateMatrix; public: □ReferenceCameras(); □void setP(); □void setC(); □void setSilhouette(); private: □cv::Mat ShilhouetteImage; □int index; □cv::Mat P; □cv::Mat C; □cv::Mat F; }; void main(){ □ReferenceCameras camera0; //この宣言でプライベートメンバのF以外に全て値が入ります □ReferenceCameras camera1;  //               〃 □CalculateMatrix::computeFundamentalMatrix( cameras0.P, cameras1.P , cameras0.C , cameras1.C , cameras1.F ); } という感じで ReferenceCameras型の camera0,camera1を作って そのCalculateMatrix::computeFundamentalMatrixの計算を行い。 camera1のFを計算する。 というのをやりたいのですが、main内のCalculateMatrix:FundamentalMatrixに引数を入れる部分でエラーが出ていてprivateメンバにアクセスできませんと出ます。 普通なら private で宣言しているので、そういうエラーが出るのは当然かと思いますが、 フレンドクラスの設定をしているのに、このエラーが出るのが理解できません。 結構調べたんですが、フレンドクラス、フレンド関数の部分と静的関数、ユーティリティ関数について絡めて解説しているのはなかったので詰まっています。 どうかみなさんの力を貸してください。 p.s. 何をやりたいのかわからん。や、定義書いてないやん。などの誹謗中傷はおやめください。心が傷つきます。

  • C++で参照カウンタを実装したいのですが

    こんにちは。 C++でクラスに参照カウンタを実装したいのですが、もしも実装する場合、 class CRefCounter {   参照カウンタとAddRef、Releaseメソッドを仮想メソッドとして実装 }; このクラスを継承して直接使う方法と、 class IRefCounter {   参照カウンタとAddRef、Releaseメソッドを純粋仮想メソッドとして宣言 } このクラスを継承して継承側で実装する方法とがあると思うのですが普通はどちらを使うものでしょうか?

  • C# 例外が発生しないことの保障

    Javaと比較して書きます。 Javaで記述した場合: public class JavaClass {  public static SampleClass s = new SampleClass(); } C#で記述した場合: public class CSharpClass {  public static SampleClass s = new SampleClass(); } JavaでもC#でも、同じコードを記述しているように見えますが、Javaではnew SampleClass()コンストラクタで例外が発生しない事が分かっているのに対して、C#の場合では例外が発生しないとは言い切れません。 これは、Javaでは、例外をスローする可能性のあるメソッド宣言では、その全てについてthrows宣言をしなければいけないのに対して、C#にはこの制約が存在しないことが原因です。 これについて何が困るかといいますと、C#で、static宣言な変数や静的コンストラクタで安易にメソッド呼び出し等を行うと、キャッチできなくなってしまいます。 public class Exceptionner {  public Exceptionner()  {   throw new ApplicationException("Exceptionnerクラスの例外");  } } public class SampleClass {  public static Exceptionner e = new Exceptionner(); // ここで例外が発生するが、キャッチできない。 } public class MyEntryPoint {  public static void Main()  {   try   {    SampleClass s = new SampleClass();   }   catch (Exception e)   {    // System.ApplicationExceptionでなくSystem.TypeInitializationExceptionとなる。    // つまり、元の例外の情報は失われている    Console.WriteLine(e.GetType());   }  } } これを現在漠然と問題視していますが、何かよい解決策はありませんでしょうか。 望んでいる解決策: ・C#でもメソッドが例外を返さないという保障がソースレベルでメソッドやコンストラクタに宣言可能? ・C#では例外をちゃんとキャッチしなくてもスマートに記述することが可能? ・問題視する必要がない?(whyも含めて)

  • 【C#】内部だけで有効なインターフェースを作りたい

    C#2005でコンポーネントを作ろうと思っています。 そこであらゆるコンポーネントに共通な内部インターフェースが存在し、 更にはコンポーネントはいくつかの種類のコンポーネントを継承したいです。 不可能なコードで記すと、このようなことがしたいです。 【拡張TextBox】 public class ExTextBox : AbstractTextBox { } 【抽象TextBox】 public abstract class AbstractTextBox : TextBox, ICommonControl {  public AbstractTextBox() {   _ifMethod();  }  private void _ifMethod() {  ←これ   // 処理  } } 【内部インターフェース】 public interface ICommonControl {  void _ifMethod(); } インターフェースはpublic宣言以外定義が行えず、内部で利用される インターフェースとしては使えません。 別にインターフェースをそのまま実装すれば出来なくはないですが、 外部にインターフェースを実装したメソッドが見えるのはマズいです。 もしくは多重継承的なことが出来れば解決すると思うのですが・・・。 コンポーネントを継承する関係で、直前のクラスはTextBoxやLabelなどと いったクラスを継承するしかない為、それ以外の内部部分を共通化 したい場合に、どうすればいいのか分かりません。 実現させる方法が思いつかない為、何かシンプルな一例をご提示 頂けないでしょうか?