#include <iostream>
using namespace std;

class Point{
private:
int x;
int y;
public:
Point(int a=0, int b=0){x=a; y=b;}
Point operator+(Point p);
};

Point Point::operator+(Point p)
{
Point tmp;
tmp.x = x + p.x; //この部分   
tmp.y = y + p.y;
return tmp;
}

int main()
{
Point p1(1, 2);
Point P2(3, 6);
p1 = p1 + p2;
}
-------------
のtmp.x = x + p.x;がなぜこうなるのか解りません。

p1 + p2;をするための前処理?なのは解るのですが。

A 回答 (2件)

p1 + p2 が、p1.operator+(p2) として実行されるのは、sssoheiさんの言う通りです。


この時 Point::operator+ 関数には、p1 のアドレスが暗黙に渡され、自動的に用意された this という名のポインタ変数に格納されます。そして p2 の値は仮引数の Point p に渡されます。
関数内にメンバ名だけで存在する x や y は、この thisポインタを暗黙に使って参照されます。

つまり実際には、次のような処理をしているのです。(あくまでイメージです。)

Point operator_plus(Point *this, Point p) {
  Point tmp;
  tmp.x = this->x + p.x;  /* p1のxメンバとp2のxメンバを足す */
  tmp.y = this->y + p.y;  /* p1のyメンバとp2のyメンバを足す */
  return tmp;
}
  :
p1 = operator_plus(&p1, p2);

結局それぞれのメンバ同士の足し算を行うわけですが、足し算結果は Point型でなければならないので、tmp という一時的に結果を格納する変数を作って、それを戻値として返すわけです。

質問されていることと違いましたら、補足をお願いします。
    • good
    • 0
この回答へのお礼

理解できました。ありがとうございました。

お礼日時:2002/02/07 19:37

「メンバ関数のオーバーロード」ではなく「演算子のオーバーロード」じゃないでしょうか^^;



たしか「p1 = p1 + p2;」というのは「p1 = p1.operator+(p2);」と言うように計算はずです。つまり、コンパイラが演算子を関数に読み替えているわけです。
# ちょっと怪しいです…^^;
そのようになっていることで、スムーズに問題が解決出来るわけです。
# 「p1 = p1 + p2 + p3;」であれば「p1 = p1.operator+(p2.operator+(p3));」という感じに

あと「return tmp;」というのは「tmp」のコピーを返しています。この様に、直接書き換えないのは「p1 = p2 + p3;」の様な時を考えてみてください。納得出来なかったら補足をお願いします。

EffectiveC++という良書(と評判です。私もそう思います)がありますので、良ければ読んでみてください。
# この項目は扱われていませんのであしからず^^;
    • good
    • 0
この回答へのお礼

ありがとうございました。本読んで見ます。

お礼日時:2002/02/07 19:38

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qオーバーロードはオブジェクト指向プログラミングの枠組みで語られるべきか

一部の書籍やサイトでは、オーバーロードがオブジェクト指向プログラミングの特徴であるかのような記述が見受けられるのですが、私はそれに疑問を感じます。
オーバーライドはクラス・継承に関わるためOOP特有のものであると思うのですが、オーバーロードはクラスとは全く切り離して考えられるからです。
確かにオーバーロードはクラスを作るときに有用な技術ではありますが、例えばC言語のような非オブジェクト指向言語でオーバーロードが使えたとしても、それなりに機能するはずです。
ひょっとしたら
「オーバーロードもオーバーライドもポリモーフィズムだろう」

「ポリモーフィズムといえばオブジェクト指向」
のような話の展開でしょうか(いや、さすがに無理があるか…)。

皆様はどうお考えでしょうか。
ご意見お聞かせ下さい。

Aベストアンサー

おっしゃるとおり、オーバーロード・オーバーライドは非オブジェクト指向言語にもありました。
オーバーロード・オーバーライドは、「異なった関数(メソッド)を同じ名前で呼び出せる・・・引数の型・数によって実際に呼び出される関数が選ばれる」というトーンですが、ポリモーフィズムは、「1つの関数(メソッド)が引き渡される引数の型・数に応じて動作を変える」というトーンだと思います。

Q{x = x>y ? x:y; return x;}

#include <iostream>
using namespace std;

inline int max(int x, int y){x = x>y ? x:y; return x;}

int main()
{
int num1, num2, ans;

cout << "2つの整数を入力して。\n";
cin >> num1 >> num2;

ans = max(num1, num2);

cout << "最大値は" << ans << "です。\n";

return 0;
}
の{x = x>y ? x:y; return x;}の部分の意味が解りません。

Aベストアンサー

inline int max(int x, int y){x = x>y ? x:y; return x;}
これを普通に関数で書くと

int max(int x, int y)
{
x = x>y ? x:y;
return x;
}

です。

x = 部分は右辺の結果が代入されます。これはわかりますよね。
x>y?x:y;
と書くと?より左にある条件式を判定し、その結果が真である場合は:で区切られた左側の値を、偽である場合は右の値を帰します。
x>yが真であればxを、偽であればyを返します。
それが、左辺値xに代入され、関数の戻り値として帰ります。

従って、2つの値をこの関数に入れると、大きいほうの値が帰ることになります。

Qオーバーロード、オーバーライド、コンストラクタについて

オブジェクト指向と言われているオーバーロード、オーバーライドの違いを詳しく教えてください。また、コンストラクタがオーバーライドするってことはあるのでしょうか??
一応、スーパークラス・サブクラスという言葉は知っています。

Aベストアンサー

オーバーロードについては他の方の説明で十分だと思います。

例えばこんな感じですね:
class A {
  public void method() {}
  public void method(int x) {}
  public void method(double x) {}
  public void method(Object x) {}
}

オーバーライドについてですが、これは分かりやすく言うとスーパークラスやスーパーインタフェースのメソッドを継承する代わりに上書きすることです。
(継承についてはお分かりですよね?)

例:
class P {
  public void method() {
    // ここで何かをする
  }
}
class Q extends P {
  public void method() {
    // ここで別な何かをする
  }
}
class R extends P {
}

PのサブクラスであるQでは、methodというメソッドを上書きしているわけです。これが「オーバーライド」です。
RもPのサブクラスですが、methodというメソッドは上書きしていません。この場合、methodというメソッドはPからRに「継承」されるのです。

なお、上書きされるメソッドが抽象(abstract)メソッドの場合、「オーバーライド」とは言わずに「実装」といいます。したがって、King-of-Walkingさんの回答に出てきたHttpServletの例は厳密には正しくありません。(もっとも、これはJavaにおける単純な言葉の使い分けの問題ですが)

なお、Javaではコンストラクタがオーバーライドされることはありえません。(オーバーロードは可能です)
コンストラクタはクラスのメンバーではないので、継承されることはありません。したがって、上書きすることもできないのです。(コンストラクタはクラスごとに独立しているということです)

ただし、Java以外のオブジェクト指向言語ではオーバーライドや継承などといった用語の意味が多少異なることがあるので注意してください。
上に書いた説明も、Java以外の言語では正しくない可能性があります。
(toginoさんが関数という言葉を用いていますが、Javaには関数と呼ばれるものは存在しません。おそらく、メソッドのことを誤って関数と呼んでいるのでしょう。言語によって用語の意味が異なるというのはこういうことです)

オーバーロードについては他の方の説明で十分だと思います。

例えばこんな感じですね:
class A {
  public void method() {}
  public void method(int x) {}
  public void method(double x) {}
  public void method(Object x) {}
}

オーバーライドについてですが、これは分かりやすく言うとスーパークラスやスーパーインタフェースのメソッドを継承する代わりに上書きすることです。
(継承についてはお分かりですよね?)

例:
class P {
  public void method() {
    // ここ...続きを読む

Qint nII[10] = { 0 }について

久々にCを使ってプログラムを組んでいるのですが、基本的な構文を思い出せず
いくつか教えていただきたく質問させていただきました。

1)配列すべてを初期化するのに、宣言時に

int nII[10] = { 0 };

で大丈夫だった(全ての要素が0で初期化)と記憶しているのですが、間違いないでしょうか?

2)構造体の初期化は

struct tm tm;
memset(&tm, 0, sizeof(struct tm))

で大丈夫でしょうか?

3)構造体の宣言は

typedef struct{
int a;
}HOGE, *LPHOGE;

HOGE st; // <- struct HOGE stと同じ
LPHOGE pst; // <- struct HOGE* pstと同じ

で問題ないでしょうか?

以上、3つ質問になって申し訳ないのですが、よろしくお願いします。

Aベストアンサー

1)OK
2)たぶんOK
3)HOGEという名前の構造体はない(当該の構造体には名前がない)ので、
// 以下のコメント記述が誤っています。ただし、

HOGE st;
LPHOGE pst;
という定義そのものはOK

Qメソッドのオーバーロードとオーバーライドのシグニチャはどうして違うの?

オーバーロードのほうはメソッド名+引数の数+引数のデータ型ですが、オーバーライドのほうはそれに加えて戻り値の型も加わります。
どうして同じではいけないのでしょうか?

Aベストアンサー

まず、シグネチャという言葉の使い方が間違っています。Javaにおいて「メソッドのシグネチャ」とは「メソッドの名前と引数の数と引数の型」という意味です。したがって「オーバーライドのシグネチャ」とか「オーバーロードのシグネチャ」などという表現は意味を成しません。「オーバーライド時に共通させるもの」などと表現してください。

> 一応どのクラスが何をするのかということを把握して作成しているものには何も不都合が感じないと思いますが。ここでは大規模開発のことで他人の作成した……

その程度ではオブジェクトの「多態性」は実現できません。
サブクラスがスーパークラスと互換性のあるインターフェースを備えていることのは多態性の必要条件です。そうでなければサブクラスにスーパークラスの振りをさせる意味がありません。(スーパークラスとサブクラスという親子関係を作る意味がないといっても良い)
二つのクラスに親子関係を作り、両者に互換性(というか共通性)を持たせようとするのであれば、オーバーライド関係にあるメソッドの振る舞い(=何という名前で何型の引数を受け取り何型の値を返すのか)が同じになるのは当然ではありませんか?

Javaは型の扱いが厳密であることも忘れないでください。JavaScriptのような、型を演算時にしかチェックしない放任主義の言語ではないのです。

参考URL:http://msugai.fc2web.com/java/polymorphism.html

まず、シグネチャという言葉の使い方が間違っています。Javaにおいて「メソッドのシグネチャ」とは「メソッドの名前と引数の数と引数の型」という意味です。したがって「オーバーライドのシグネチャ」とか「オーバーロードのシグネチャ」などという表現は意味を成しません。「オーバーライド時に共通させるもの」などと表現してください。

> 一応どのクラスが何をするのかということを把握して作成しているものには何も不都合が感じないと思いますが。ここでは大規模開発のことで他人の作成した……

その程度...続きを読む

Qfor(s=p; *p; p++)の*p(ポインタ)の意味

for(s=p; *p; p++)の*p(ポインタ)の意味
C言語初心者です。
今ポインタを勉強しているのですが、
for文で上記のようなものが出てきて、意味が分からず困っています。
*pで*p != NULL と同じような意味になるみたいなのですが…。
どうしてそのような意味になるのでしょうか?

ちなみにsとpはポインタで、
sには配列(入力した文字列)の先頭アドレスが入っています。
pは文字列を指していて○○○○○NULL ←になるから上記のような条件で
回るんだろうなぁとはなんとなく考えているのですが。

Aベストアンサー

念のため:
ヌルポインタは「ビットパターンとして」0 じゃないかもしれませんが, ソースプログラムにおいて「ポインタが要求される場面」で「0」とあれば, それは「ヌルポインタ」です.
もうちょっと厳密に書くと「整定数 0」はヌルポインタに変換される.

Qオーバーロードされたメンバ関数のポインタをとる

オーバーロードされたメンバ関数のポインタをとるにはどうしたらよいでしょうか?
具体的には前置インクリメント演算子 ++()と、後置インクリメント演算子 ++(int)の両方のをオーバーロードしたときに両方のメンバ関数ポインタがとりたいです。
環境はVC7.1です。
よろしくお願いします。

Aベストアンサー

クラス X に対して前置/後置インクリメントはそれぞれ
X &X::operator ++();
X operator ++(int);
と定義するのが普通なので, それにあわせて
X &(X::*preinc)() = &X::operator++;
X (X::*postinc)(int) = &X::operator++;
でとれないですかね? Visual Studio 2008 だとこれでいけるんですが.

Qint i,j; \n i=0,j=5;

int i,j;
i=0;
j=5:
と書いてあるソースは普通ですが、
int i,j;
i=0,j=5:
と書いてあるソースもあります。
後者はC++の正しい書式ですか?

カンマ演算子というのは後者のカンマのことですか?

Aベストアンサー

 正しい書式です。

i=0,j=5;
 における、「,」をカンマ演算子といいます。2項の演算子です。カンマで区切られた演算を「左から順番に」実行し、最後の演算を結果として返します。
 したがって、例の文であれば、i=0を実行し、次にj=5を実行。そして、j=5の結果の5を結果として返します。
 ・・・
 が、本来的には、あまり、例のような使い方はしませんね。よく見られるのは、次のような場合です。

 for (i=0,j=0 ; i < 50 ; ++i,++j) {

 のような形でよく見られます。for文の各式は、一つの式でなければならないので、こんな書き方をするわけです。初期化と更新部が一つにまとまり、ループが読みやすくなるのが利点かな。

Q+演算子オーバーロード

こんにちは。お世話になっております。

// +演算子オーバーロード
CPoint CPoint::operator+(CPoint& obj) //~(1)
{
CPoint tmp;
tmp.m_x = m_x + obj.m_x;
tmp.m_y = m_y + obj.m_y;
return tmp;
}
int main()
{
CPoint point1( 100, 150 );
CPoint point2( 200, 50 );

std::cout << "x:" << point1.getx() << "y:" << point1.gety() << std::endl;
point1 = point1 + point2; // オーバーロードされた+演算子が呼び出される
std::cout << "x:" << point1.getx() << "y:" << point1.gety() << std::endl;
point1 += point2; // オーバーロードされた+=演算子が呼び出される
std::cout << "x:" << point1.getx() << "y:" << point1.gety() << std::endl;
return 0;
}
某サイトで上のようなサンプルプログラムがあるのですが
これはc++で書かれた「+演算子オーバーロード」の定義で、動作としては
「point1 = point1.operator+( point2 ); // point1 = point1 + point2; と同じ」というような動作です。
それで疑問が出てきたのですが、イコールの右側で足す数が↓のような3つの場合、ans = a + b + c;です。
これだと(1)のところの引数を2つをとる関数を別に作らないとだめでしょうか?それとも、ans = ((a + b) + c);というふうに優先順位で自動的に計算してくれる+演算子オーバーロードのプログラムを教えてくれませんか?↑式のカッコは便宜上付けただけで、出来ればans = a + b + c;だけで計算出来るプログラムを教えてください。

こんにちは。お世話になっております。

// +演算子オーバーロード
CPoint CPoint::operator+(CPoint& obj) //~(1)
{
CPoint tmp;
tmp.m_x = m_x + obj.m_x;
tmp.m_y = m_y + obj.m_y;
return tmp;
}
int main()
{
CPoint point1( 100, 150 );
CPoint point2( 200, 50 );

std::cout << "x:" << point1.getx() << "y:" << point1.gety() << std::endl;
point1 = point1 + point2; // オーバーロードされた+演算子が呼び出される
std::cout << "x:" << point1.getx() << "y:" << point1.gety()...続きを読む

Aベストアンサー

CPoint CPoint::operator+(CPoint& obj)
ひとつ用意すれば
連続して3つでも4つでも、いくつでも加算可能です。

Qfor(int i = 100, long n = 1; i > n/3i; i++)

for(int i = 100, long n = 1; i > n/3i; i++)
のように、初期設定で型の違う変数を宣言したいんだけど
C++ではこんなふうに2つ以上の型を宣言してはいけないんですか?

Aベストアンサー

,

コンマ演算子の原理です。
forの初期化文で "," で区切れるのは値を返す文だけです。
よってintステートメントもlongステートメントも値を返さないので、この文では使用できません。

というか、むしろ、intステートメントの第2引数としてlongが認識されてしまいます。
外で

int i; long n;

とし

for(i = 0, n = 0; hoge; hoge)

なら可能です。


人気Q&Aランキング