• ベストアンサー

演算子のオーバーロード

座標を表すクラスとして class Point { public:  double *buf;  Point(double, double) {   printf("new :%p ", buf);   buf = new double[2];   buf[0] = x1;   buf[1] = x2;   printf("-\n");  }  ~Point() {   printf("delete :%p ", buf);   delete [] buf; // ※1   printf("- \n");  }  Point operator +(Point){   Point a(0.0, 0.0);   a.buf[0] = this->buf[0] + p.buf[0];   a.buf[1] = this->buf[1] + p.buf[1];   return a;  }  Point operator =(Point){   this->buf[0] = p.buf[0];   this->buf[1] = p.buf[1];   return *this; // ※2  } }; int main() {  {   Point a(1.0, 2.0);   Point b(3.0, 4.0);   a = a+b; //(1)   a = a+b+a+b; //(2)   a = (a=b) + (b+b); //(3)   printf("(%f, %f)\n", a.buf[0], a.buf[1]);  }  return 0;  } を作成し、(1),(2),(3)のいずれかを記述して実行したところ、 (1) 正常に動作(4,6) (2) セグメンテーションフォルト ※1 を削除すると(8,12) (3) セグメンテーションフォルト ※1 を削除すると(9,12) という結果になりました。 Deleteで(同じアドレスを開放しようとして)失敗しているようなのですが、思った動作をさせるためにはどうすればよいでしょうか。 標準出力を載せたいのですが、文字数制限により無理のようなので、後ほど補足致します。 環境 Windows XP SP2 Cygwin 1.5.19(0.150/4/2) GCC 3.4.4

  • arcsin
  • お礼率46% (194/417)

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

  • ベストアンサー
  • mizuneko
  • ベストアンサー率16% (3/18)
回答No.3

ANO.2です。 Point operator+(const Point& p) ではなく、 Point operator+(const Point& p) const でした。 申し訳ありません。

arcsin
質問者

お礼

いえ、ソースコード大変参考になりました。 参照で渡すとよいのですね。 自分の知識不足で、operator= の戻り値を参照にする点と > Point operator+(const Point& p) const という記述方法がなぜそうする(べきな)のかがちょっとわからないのですが、その辺は自分で調べてみます。 ご回答ありがとうございました。

その他の回答 (2)

  • mizuneko
  • ベストアンサー率16% (3/18)
回答No.2

jactaさんの言われるように、 コピーコンストラクタ定義したら動きました。 ただ個人的には、代入演算子の方が気になってしまいます。 参照をとって、参照を戻す形にしたほうがよいように思いますが、 どうでしょうか。 #include <stdio.h> class Point { public: double *buf; Point(double x1, double x2) : buf(new double[2]) { buf[0] = x1; buf[1] = x2; printf("new :%p -\n", buf); } Point(const Point& p) { buf[0] = p.buf[0]; buf[1] = p.buf[1]; } ~Point() { delete [] buf; printf("delete :%p -\n", buf); } Point operator+(const Point& p){ return Point(buf[0] + p.buf[0], buf[1] + p.buf[1]); } Point& operator=(const Point& p){ buf[0] = p.buf[0]; buf[1] = p.buf[1]; return *this; } }; int main() { Point a(1.0, 2.0); Point b(3.0, 4.0); a = a+b; a = a+b+a+b; a = (a=b) + (b+b); printf("(%f, %f)\n", a.buf[0], a.buf[1]); return 0; }

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

あまり詳しく見ていないので、当て推量に近いですが... コピーコンストラクタが定義されていないのが直接の原因かと思います。 デフォルトのコピーコンストラクタでは、単にbufの値をコピーするだけで、領域は再確保しませんから、デストラクタで同じ領域を二重解放しているのでしょう。

arcsin
質問者

お礼

恥かしながら「コピーコンストラクタ」という存在を初めて知りました。 まだまだ知識不足ですね… (コンストラクタで作成していないメモリ領域を開放しようとしているから変だな~と悩んでました) ご回答ありがとうございます。

関連するQ&A

  • new演算子のオーバーロードについて

    #include <stdio.h> #include <windows.h> class MyNew { public: void* ptr; MyNew( void* p ) { ptr = p; } void* MyNew::operator new( size_t size ) { printf("new-\n"); return malloc( size ); } void MyNew::operator delete( void* ptr ) { printf("delete-\n"); free( ptr ); } }; void main( void ) { MyNew p = new int; } クラスのメモリ確保をnew演算子のオーバーロードを用いて書いてみたのですがオーバーロードしたnew演算子が呼ばれません。 なぜでしょうか? /** VisualStdio2005コンソールアプリケーション WindowsXP */

  • operator=()のオーバーロード。

    C++で簡単な多次元ベクトルを扱うクラスをつくっているのですが、 operator=()の実装で躓いてしまいました。 過去ログでは void operator=(CHoge& hoge){ (略) } という実装のアドバイスを見つけられたのですが、 これではa = b = c;といったような代入ができません。 結局*thisを返すように実装しているのですが、うまくいかない原因がどうしてもうまくいかないので、どなたか教えていただけないでしょうか? --------------------------- Windows XP SP2 Microsoft Visual Studio.net theSpokePremium version --------------------------- class vector{ public: /* (中略) */ vector(int dimensions) : d(dimensions) { v = new double[d]; for(int i = 0; i < d; i++){ v[i] = 0.0; } } /* (中略) */ void set(int dimension, double x) { v[dimension] = x; } int size() { return d; } /* (中略) */ vector operator=(vector& right) { if(right.d != d) return INVALID_VECTOR; for(int i = 0; i < d; i++){ v[i] = right.v[i]; } return *this; } /* (中略) */ private: int d; // ベクトルの次元 double *v;// 各成分 } --------------------------- int main() { vector a(3); // a(0.0, 0.0, 0.0) a.set(0, 1.0); // a(1.0, 0.0, 0.0) vector b(3); // b(0.0, 0.0, 0.0) b.set(1, 2.0); // b(0.0, 2.0, 0.0) b = a; for(int i = 0; i < b.size(); i++){ printf("%f ", b.get(i)); } printf("\n"); return 0; } ---------------------------

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

    こんにちは。お世話になっております。 // +演算子オーバーロード 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;だけで計算出来るプログラムを教えてください。

  • メンバ関数のオーバーロード

    #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;をするための前処理?なのは解るのですが。

  • 演算子のオーバーロードについて

    []演算子のオーバーロードでつまづきました。 代入文で左辺、右辺、両方ともに[]演算子を使う場合 int &operator[](int i) { return a[i]; } int &operator[]のようにして、戻り値を参照型にしています。 このとき、main関数内で、 ob1[2]=ob2[2];(ob1,ob2はoperator[]関数が関連付けられているクラスのオブジェクト) のようにすると、左辺(ob1)にちゃんと代入されています。 つまりこの場合、main()関数内で、 (int &)型の(this->a[i])(元のオブジェクトは、ob1) に (int &)型の(this->a[i])(元のオブジェクトは、ob2)を代入しているのでしょうか?

  • C#における++演算子のオーバーロードについて

    はじめまして。 いろいろ調べてみたのですが、わからなかったので、質問させてください。 C#における++演算子のオーバーロードについてなのですが、 まずは、以下のコードをご覧ください。 ================================================================ using System; class Test { private int Num; public Test(int x) { this.Num = x; } public static Test operator ++(Test t) { Test result = new Test(t.Num + 1); return result; } public override string ToString() { return this.Num.ToString(); } } class TestDemo { public static void Main() { Test t = new Test(0); Console.Write(t++ + "\n"); Console.Write(t + "\n"); Console.Write(++t + "\n"); Console.Write(t + "\n"); } } ================================================================ 実行結果 0 1 2 2 ================================================================ ++演算子のオーバーロード関数の実装が一つなのに 前置インクリメントと後置インクリメントが適切に行われています。 二つのインクリメントが行われるときに同じメソッドが 呼び出されていると思うのですが、同一の実装で、振る舞いが 異なるのは、なぜなのでしょうか?どのようなカラクリで 実行されているのでしょうか?全くわかりません。どなたか 教えてください。よろしくお願いします。

  • C++で>>演算子のオーバーロード

    C++学習者です。 Visual Studio Community 上で、ある教本を使って勉強しています。 現在Stringというクラスを作って、文字列に対して連結や部分文字列の取り出しなどができるようにするための色々な演算子のオーバーロードをする関数を定義していますが、疑問点がありますので、お聞きしたいと思います。 Stringクラスのプライベート変数は、文字列の長さを表すlength と、new 演算子で動的に確保するメモリー領域の始まりのアドレスを表す *sPtr の二つです。 クラス内ではパブリックなメンバー関数としていろいろな演算子がオーバーロードされていて、これらについてはよく理解できるのですが、friend 関数として定義されている入力演算子(>>)について納得がいかない部分があります。 その関数は次のようになっています。 istream &operator>>(istream &input, String &s) { char temp[100]; input >> setw(100) >> temp; s = temp; return input; } わからないのは s = temp; の部分です。 sはStringクラスのオブジェクトで、temp は単なる文字列なのに、なぜ代入できるのでしょうか? 代入演算子=のオーバーロード関数も下に挙げますが、この中でも単なる文字列をStringクラスのオブジェクトに代入できるようにはなってないように見えます。 const String &String::operator=(const String &right) { if (&right != this){ // avoid assignment of itself delete [ ] sPtr; length = right.length; sPtr = new char[ length + 1]; strcpy(sPtr, right.sPtr); } else cout<< "attempted to assign a String to itself \n\n"; return *this; } どなたか答えて頂けると有難いです。

  • c++のnew演算子をオーバーロードできるものの、

    c++のnew演算子をオーバーロードできるものの、 delete演算子をオーバーロードできなくて悩んでいます。 コンパイルは通るのですが、ランタイム時に ペアとなるdeleteが呼ばれません。 inline void* operator new(size_t size, const char* filename , int line , const char* funcname ) { return my_local_malloc( size , filename , line , funcname ); } inline void operator delete(void* pMem, const char* filename , int line , const char* funcname ) { my_local_free( pMem , filename , line , funcname ); } deleteも確実にオーバーロードできる方法を ご存知のかた、お教え願います。

  • 多次元配列の new 2

    追加の質問ですみません^^; char の8個の配列へのポインタの配列を new する場合などは、以下のサンプルのように typedef しないとかけないんでしょうかね?たとえば、  char (**bb)[8] = new (char (*)[8])[8]; 書きたいように思いますが、これは文法違反ですし・・・^^; ==== サンプル:(iostream の初期化時に、定義した new が呼び出されるかもしれないことを一応考慮して、stdio の関数を使っています^^) #include <new> #include <stdlib.h> #include <stdio.h> void *operator new(std::size_t s) { void *p = malloc(s); fprintf(stderr, "::new(): %p\t%lu\n", p, (unsigned long)s); return p; } void operator delete(void *p) { fprintf(stderr, "::delete(): %p\n", p); if (p) free(p); } void *operator new[](std::size_t s) { void *p = malloc(s); fprintf(stderr, "::new[](): %p\t%lu\n", p, (unsigned long)s); return p; } void operator delete[](void *p) { fprintf(stderr, "::delete[](): %p\n", p); if (p) free(p); } int main() { typedef char (*T)[8]; char (**b)[8] = new T[8]; delete[] b; } ==== % ./a.exe ::new[](): 0x6e01b0 32 ::delete[](): 0x6e01b0

  • 書式付標準出力をするには??

    こんにちは テキストファイルを読み込んで .hファイルに書き込んでいるものなのですが.... #include <stdio.h> #define MAX 256 int main() { FILE *in, *out; char *p, buf[MAX]; int lhs, in_quote; in = fopen("moutput.txt", "r"); if (in == NULL) { printf("Cannot open sample.txt\n"); return 1; } out = fopen("moutput.h", "w"); if (out == NULL) { printf("Cannot open sample.h\n"); return 1; } while (fgets(buf, MAX, in) != NULL) { lhs = 1; in_quote = 0; for (p = buf; *p != '\0'; p++){ if (*p == '=') { lhs = 0; fputc('\n', out); } else if (*p == '"'){ if (in_quote) { in_quote = 0; fputc('\n', out); } else in_quote = 1; }else if (lhs || in_quote){ fputc(*p, out); } } } } 上記のプログラムでfputc(*p,out)で出力させている 部分があると思いますが。 実はこれを書式付で出力させたいと思っています。 今現在読み込んでいるファイルは "POINT_a"="POINT_b"+1000*"POINT_D" で出力結果は POINT_a POINT_b POINT_D なのですが これを VALUE: POINT_a VALUE: POINT_b VALUE: POINT_D にしたいのですが fputcのところをどうしたらいいでしょうか?? ご教授よろおしくおねがいします。

専門家に質問してみよう