-PR-
解決済み

二項演算子のオーバーライドについて

  • 暇なときにでも
  • 質問No.61565
  • 閲覧数448
  • ありがとう数4
  • 気になる数0
  • 回答数3
  • コメント数0

お礼率 14% (3/21)

目黒@C++学習中 です。

二項演算子のオーバーライドする時
どうして"friend"にしないといけないの?

以下テスト ソース

#include <windows.h>

#pragma warning(push,3)
#include <iostream>
#include <iomanip>
#pragma warning(pop)

using namespace std;


class clsTest
{
private:
double m_dNum;
public:
clsTest() : m_dNum(0) {}
clsTest(double dNum) : m_dNum(dNum) {}
~clsTest(){};
friend clsTest operator + (const clsTest oP1,const clsTest oP2) {
return clsTest(oP1.m_dNum+oP2.m_dNum);
}
friend ostream& operator << (
ostream& oOutStream,const clsTest oT
) {
return oOutStream << "T(" << oT.m_dNum <<")";
}
};

void main()
{
clsTest oT1(2);
clsTest oT2(5);
clsTest oT3 = oT1 + oT2;

cout << setiosflags(ios::fixed) << setprecision(4);
cout << oT1 << endl;
cout << oT2 << endl;
cout << oT3 << endl;
}
通報する
  • 回答数3
  • 気になる
    質問をブックマークします。
    マイページでまとめて確認できます。

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

  • 回答No.1
レベル14

ベストアンサー率 50% (1122/2211)

それは、あなたがやっているのが「メソッドのオーバーライド」ではなく、
「関数のオーバーロード」だからです。

クラスの宣言の中に実装を書いているので分かり難いですが、実装を
分離すると、

class clsText {
...
friend clsTest operator + (const clsTest oP1,const clsTest oP2);
friend ostream& operator << (ostream& oOutStream, const clsTest oT);
};

clsTest operator + (const clsTest oP1,const clsTest oP2)
{
  return clsTest(oP1.m_dNum+oP2.m_dNum);
}
ostream& operator << (ostream& oOutStream, const clsTest oT)
{
  return oOutStream << "T(" << oT.m_dNum <<")";
}

となります。両方ともグローバルなスコープを持つ + と << を
追加しているだけです。グローバルな関数の実装をしているのです
から、private なメンバを触るためには friend 宣言が必要になります。

operator+ は、メソッドのオーバーライドでも記述できます。


class clsText {
...
clsTest operator + (const clsTest oP2);
};

clsTest clsText::operator + (const clsTest oP2)
{
  return clsTest(m_dNum + oP2.m_dNum);
}

違いが分かりますか?
補足コメント
nakashi

お礼率 14% (3/21)

では逆に Add関数をグローバルにする方法は?

class clsTest
{
private:
double m_dNum;
public:
clsTest() : m_dNum(0) {}
clsTest(double dNum) : m_dNum(dNum) {}
void Add(clsTest oT1,clsTest oT2) {
m_dNum = oT1.m_dNum + oT2.m_dNum;
}
// friend clsTest Add(clsTest oT1,clsTest oT2){}
};

void main()
{
clsTest oT1(2);
clsTest oT2(5);
clsTest oT3;

oT3.Add(oT1,oT2);
// oT3 = Add(oT1,oT2) こう書きたい
}

#クラスの基本的な理解が欠けているみたいで、すみません
#このへんのことが書いてある おすすめの本があれば教えて下さい
投稿日時 - 2001-04-09 15:26:43
-PR-
-PR-

その他の回答 (全2件)

  • 回答No.2
レベル14

ベストアンサー率 50% (1122/2211)

> では逆に Add関数をグローバルにする方法は?

class clsTest {
private:
  double m_dNum;
...
  friend clsTest Add(const clsTest& oT1, const clsTest& oT2);
};

void clsTest Add(const clsTest& oT1, const clsTest& oT2)
{
  return clsTest(oT1.m_dNum + oT2.m_dNum);
}

クラス宣言の中に実装を書いてしまうと、friend宣言が無いと、
メソッドとしてコンパイルされてしまいます。

friend宣言をしているのは、private なメンバーを参照して
いるからです。

また、関数 Add の引数が const な参照になっているのは、
必須ではありませんが、普通(*)はこう書きます。

  (*) 参照ではないと、無駄なインスタンスの複写が行われる

因みに、最初の回答のときには気がつきませんでしたが、
operator+ の引数も const な参照になっているべきです。


  • 回答No.3
レベル11

ベストアンサー率 61% (157/255)

? 根本的にわかってないような・・・C++の悪い記述の習慣を真似しているように見える・・・

friend など使う場面は比較的少ないです。

二項演算子オーバーライドについては、クラスの外に出してやる必要性があります。
これは例えば、文字列型とかで考えればわかりやすい。

string s;
s = "abc" + s;   --------(1)

クラス中のメソッドとして、演算子オーバーライドしてしまうと、(1)に対処させることができない。"abc"はchar* 型であり、 char*クラスにメソッドを付け加えることができない。だから、やむをえず、普通の関数オーバーライドと言う形をとるわけですね。


で。。。。

friend ostream& operator << (
ostream& oOutStream,const clsTest oT
) {
return oOutStream << "T(" << oT.m_dNum <<")";
}
};

このなかで、クラス内のプライベートメンバーに『強引に』アクセスしているから、friendが必要になってしまっている。
しかし、考えなければならない。本当にfriendは必要なのか?
もっといえば、double m_dNum の値を外部から取得されてはまずいのか?

こたえは否のはず。
double m_dNumというメンバーに直接触れられてはまずいが、m_dNumの値を外とやり取りすることは、例えば、setNum(cls Test&) や getNum()を定義することによって可能とするべきだろう。

すなわち、m_dNumの値は、クラスの外とやりとりしても良い。
m_dNumという『メンバーの名前』に触れられては困るが、『値』をやり取りされるのはOKなのだ。

そうなれば、

friend ostream& operator << (
ostream& oOutStream,const clsTest oT
) {
return oOutStream << "T(" << oT.m_dNum <<")";
}
};
このような定義の仕方は不適切であるとわかる。
おそらく、それは

ostream& operator <<(ostream& oOutStream, const& clsTest oT) {
return oOutStream << "T(" << oT.getNum() << ")";
}

という形にすることによって、2項演算子多重定義をクラスの内部の実装に触れさせることなく実現させることができる。

一方friendを使用するのは、
『メンバーの名前』の隠蔽性を犠牲にしてでも、いかなることがあっても『値』に触れさせてはまずいクラスフィールドに対して2項演算子オーバライド関数内でアクセスする場合である。

外部からその『値』をふれさせて良いかダメかは、set値 get値 といったメソッドを実装することが妥当かどうかで判断できるであろう。
このQ&Aのテーマ
このQ&Aで解決しましたか?
AIエージェント「あい」

こんにちは。AIエージェントの「あい」です。
あなたの悩みに、OKWAVE 3,500万件のQ&Aを分析して最適な回答をご提案します。

-PR-
-PR-
こんな書き方もあるよ!この情報は知ってる?あなたの知識を教えて!
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-
-PR-
-PR-

特集


専門家があなたの悩みに回答!

-PR-

ピックアップ

-PR-
ページ先頭へ