• ベストアンサー

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; } ---------------------------

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

  • ベストアンサー
  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.2

No.1です。 おおぼけ。 > return &*this; < return *this; 参照は値と同じ記述でしたね。 # ちょっと書いてないと記述が危うくなる

yu-ta19
質問者

お礼

#1へのお礼も兼ねて。 ありがとうございます。 解決しました。 C++の参照がまだいまいち理解しきれてないので勉強して出直してきます。

その他の回答 (3)

  • ddnp009
  • ベストアンサー率25% (15/58)
回答No.4

operator=()の実装については、#1さんと#2さんの 回答どおり、すなわち参照として*thisを返すこと。 コトバの意味がはっきりしていません。 >多次元ベクトル どこが多次元なんですか?配列のラッパーにしか見えない。 要素がdouble固定ということは、各要素の型が class vectorではないのですよね。 >うまくいかない原因がどうしてもうまくいかない 落ち着いて、投稿する前に読み直してみましょう。 そもそも、どのように動いて欲しいのか不明。 最後に、あえてstd::vectorを使わずに 自前のvectorを書いているのは勉強のためですよね?

yu-ta19
質問者

お礼

> どこが多次元なんですか?配列のラッパーにしか見えない。 そうですね。この部分だけだと単なるラッパーですが、多次元配列ではなく「数学の」多次元ベクトルクラスとして完成させたいと思っています。 #1さんへの補足としてリンクを貼りましたが、少しづつ数学演算を追加していきます。 > 落ち着いて、投稿する前に読み直してみましょう。 > そもそも、どのように動いて欲しいのか不明。 確かに日本語がおかしいですね、整形しようとしてるうちにおかしくなってしまったようです。。 読みづらい文章で申し訳ありません。 知りたいのはoperator=()の正しい実装という一点、動作はベクトル各要素への代入です。 →for(int i = 0; i < d; i++) v[i] = right.v[i]; 最後に、 > あえてstd::vectorを使わずに > 自前のvectorを書いているのは勉強のためですよね? 目的の半分は勉強、 残り半分は自前の数学演算クラスが欲しいからです。 数学という前提があればstd::vectorではあんまりなので。 確かに自分の言葉足らずでした。 今回は既にご回答をいただくことができましたが、 以後気を付けるようにします。 回答ありがとうございました。

回答No.3

回答は既にある通りですが、ちょっと補足を。 a = b = c; という記述は、見かけ上、a と b に c を代入しているように見えますが、= は、 + や - と同じ2項演算子です。 ですから、 a = b = c; は、 a = (b = c); という意味です。 つまり、 1)b に c を代入する。その代入式の値は c 2)a に、(b = c) の結果を代入する。 という2段階の動作が(意味的には)発生します。 このために、このような操作を行うためには、operater=() は、operater=() の引数に変換可能な型を返す必要があります。 つまり、 vector& operator=(vector& right); となるわけですね。

yu-ta19
質問者

お礼

> という2段階の動作が(意味的には)発生します。 ここまでは理解できていたのですが・・・。 その先がまだまだ理解不十分でした。 ありがとうございます。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

連続代入するには代入演算子はオブジェクトへの参照を返さないといけません。 基本的には vector& operator=(vector& right) { /* 中略 */ return &*this; } のような記述にすると思います。

yu-ta19
質問者

補足

800字制限で補足ができませんでした。 といってももう返答をいただいてしまいましたが・・・。 ---------------------------[実行結果] -26569842580370804000000000000000000000000000000000000000000000000000000000000000000000000.000000 -26569842580370804000000000000000000000000000000000000000000000000000000000000000000000000.000000 -26569842580370804000000000000000000000000000000000000000000000000000000000000000000000000.000000 --------------------------- [プログラム全体] http://www.geocities.jp/bethrned/vector.h.html http://www.geocities.jp/bethrned/test.cpp.html --------------------------- よろしくお願いします。

関連するQ&A

  • vectorを使用したときのクラス定義について

    現在C++で、STLのvectorを学習しているのですが、 本を見ると ベクトルに保存されるクラスオブジェクトについて 「"<" および "=="を定義する必要がある」 っと書いてあります。 実際のサンプルなどでは、(長くなってしまってすみません) // ベクトルにクラスオブジェクトを保存する #include <iostream> #include <vector> using namespace std; class Demo { double d; public: Demo() { d = 0.0; } Demo(double x) { d = x; } Demo &operator=(double x) { d = x; return *this; } double getd() { return d; } }; bool operator<(Demo a, Demo b) { return a.getd() < b.getd(); } bool operator==(Demo a, Demo b) { return a.getd() == b.getd(); } int main() { vector<Demo> v; int i; for(i=0; i<10; i++) v.push_back(Demo(i/3.0)); for(i=0; i<v.size(); i++) cout << v[i].getd() << ' '; cout << endl; for(i=0; i<v.size(); i++) v[i] = v[i] .getd() * 2.1; for(i=0; i<v.size(); i++) cout << v[i].getd() << ' '; cout << endl; return 0; } っというように書かれています。 ここで、なぜ<や==演算子をオーバーロードする必要があるのかが わかりません。 VC6.0やbccコンパイラで、演算子のオーバーロード箇所をコメントにしても通ってしまいます。 また、本には、「コンパイラによってはその他の比較演算子の定義も必須とされています」っとあります。 お手数おかけしますが、この辺りのことを簡単に(初心者なので・・・)教えていただけたら。と思います。 よろしくお願いします。

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

    []演算子のオーバーロードでつまづきました。 代入文で左辺、右辺、両方ともに[]演算子を使う場合 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++で書かれた以下のプログラムのコンパイルができません。理由を教えてください。 #include <iostream> #include <vector> #include <algorithm> istream& read(istream&, std::vector<double>&); double median(std::vector<double>); int main(){ std::vector<double> a; read(std::cin, a); std::vector<double>::iterator itr; while(itr != a.end()){ std::cout << *itr; } std::cout << median(a) << std::endl; } istream& read(istream& is, std::vector<double>& v){ double b; if(is){ while(in >> b) v.push_back(b); } return is; } double median(std::vector<double> a){ int i; if(a.size() == 0) { return -1; } i = a.size() / 2; if(a.size()%2 == 1) return (a[i]); else return ((a[i] + a[i-1])/2); }

  • 2次元配列にポインタを格納

    http://www.okweb.ne.jp/kotaeru.php3?q=505241の訂正版の質問です。 VC++6.0を使っております。 下のようなプログラムを作ってみました。 #include <stdio.h> #include <vector> using namespace std; class c{ public: c(); virtual ~c(); int get(){return j;}; void set(int i){j=i;}; private: c(const c &right); const c &operator=(const c &right); int j; }; void main(){ vector <vector<c*> > a; c *b; for(int n=0;n<10;n++){ for(int i=0;i<10;i++){ b=new c; a[n].push_back(b); } } for(int j=0;j<10;j++){ for(int i=0;i<9;i++){ a[i][j] -> set(i+j); } } for(j=0;j<10;j++){ for(int i=0;i<9;i++){ printf("%d ",a[i][j] -> get()); } printf("%d\n",a[9][j] -> get()); } for(int i=0;i<10;i++){ for(int j=0;j<10;j++){ delete a[i][j]; } } } すると、コンパイルには成功するのですが、実行は出来ません。 その理由は、「外部参照1が未解決」だそうです。 アドバイスをお願いいたします。

  • C#のプログラミングについて(基礎・・)

    どうしても エラーが出ます エラーの表示は 下のようなものなのですが、どういう意味かわかりません。 C:\Documents and Settings\gc60117\デスクトップ\Project3\CodeFile1.cs(20): 引数を '2' 個指定できる、メソッド 'Vector' のオーバーロードはありません。  自分なりのプログラミングデータを記述します。 間違いを指摘していただけると助かります。 using System; class Vector { private double x; private double y; public double Length { get{return Math.Sqrt(x*x+y*y);} } public void Write() { Console.Write("({0},{1})",x,y); } public static Vector I { get{return new Vector(1,0);} } public static Vector J { get{return new Vector(0,1);} } public static Vector operator*(double k,Vector a) { Vector t= new Vector(); t.x=k*a.x; t.y=k*a.y; return t; } public static double operator*(Vector a, Vector b) { double z= new double(); z=a.x*b.x+a.y+b.y; return z; } public static Vector operator+(Vector a,Vector b) { Vector u=new Vector(); u.x=a.x+b.x; u.y=a.y+b.y; return u; } public static double Angle(Vector A,Vector B) { double r=new double(); r=A*B/(A.Length*B.Length); r=Math.Acos(r); r=r/6.28*360; return r; } } class kadai53 { static void Main() { Vector A; double x, y; Console.Write("ベクトルAの成分を入力してください\n"); Console.Write("x成分は ? "); x = double.Parse(Console.ReadLine()); Console.Write("y成分は ? "); y = double.Parse(Console.ReadLine()); A = x * Vector.I + y * Vector.J; //静的プロパティと,一つ目の*演算子,+演算子の呼び出し Console.Write("A = "); A.Write(); Vector B = new Vector(0, 1); Console.Write("\nB = "); B.Write(); Console.WriteLine("\nベクトルAとベクトルBの内積の値は{0}です", A*B);//二つ目の*演算子の呼び出し Console.Write("ベクトルAとベクトルBがなす角度は{0}度です\n", Vector.Angle(A,B)); } }

  • Javaのオーバーロードを使った問題

    class Book{ String title, size; int price; Book(String title, String size, int price){ this.title = title; this.size = size; this.price = price; } public String info(){ return title + " " + size; } public String info(String title){ return title + " " + size + " " + price +"円"; } public int info(String title, String size){ return price; } } ________________________________________________________ class Book_test{ public static void main(String[] args){ String[] title = {"図鑑","参考書","雑誌","地図"}; String[] size = {"B4", "A5", "A4", "A3"}; int[] price={4500, 1800, 600, 1400}; Book[] b = new Book[4]; for(int i=0; i<b.length; i++){ b[i] = ****; } for(int i=0; i<b.length; i++){ System.out.println(***); } for(int i=0; i<b.length; i++){ System.out.println(***); } for(int i=0; i<b.length; i++){ System.out.println(***); } } } 実行結果は、以下の通り 図鑑 B4 参考書 A5 雑誌 A4 地図 A3 図鑑 B4 4500円 参考書 A5 1800円 雑誌 A4 600円 地図 A3 1400円 4500 1800 600 1400 このように表示するために、javaのソースコードを書かなくてはならないのですが、***の部分に何を入れれば良いのか分かりません。 特に、for文の部分です。 classが苦手なので分かりやすく教えていただけると幸いです。

    • ベストアンサー
    • Java
  • C++の質問です

    C++の質問です。 c++をコンパイルしたとき、 出力されるのが次のように3つ同時にされるようにしたいのですが、 1、 名前 ○○○○ 番号 ○○○○ x= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}の平均 2、 x= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}の分散 y= {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}の標準偏差 3、 x={1,2,3,4,5,6,7,8,9,10}と y={10,9,8,7,6,5,4,3,2,1}の相関係数 下記のソースをどのように変えればいいでしょうか。 ちなみに、C言語ではなくC++なので C++形式でお願いします。 どうかお願いします。 #include <iostream> #include <cmath> using namespace std; double Mean(int *a, int size); double StandardDeviation(int *a, int size); double CoefficientOfCorrelation(int *a, int *b, int sizeA, int sizeB); int main() { int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int y[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; cout << " 標準偏差 : " << StandardDeviation(x, sizeof(x) / sizeof(int)) << endl << " 相関係数 : " << CoefficientOfCorrelation(x, y, sizeof(x) / sizeof(int), sizeof(y) / sizeof(int)) << endl; return 0; } double Mean(int *a, int size) { if (size <= 0) { return -1.0; } double d = 0.0; for (int i = 0; i < size; i++) { d += *(a + i); } return d / size; } double StandardDeviation(int *a, int size) { if (size <= 0) { return -1.0; } double mean = Mean(a, size); double d = 0.0; for (int i = 0; i < size; i++) { d += pow(*(a + i) - mean, 2); } return sqrt(d / size); } double CoefficientOfCorrelation(int *a, int *b, int sizeA, int sizeB) { if (sizeA > 0 && sizeB > 0 && sizeA != sizeB) { return -1.0; } double meanX = Mean(a, sizeA); double meanY = Mean(b, sizeB); double sdX = StandardDeviation(a, sizeA); double sdY = StandardDeviation(b, sizeB); double coeff = 0.0; for (int i = 0; i < sizeA; i++) { coeff += (*(a + i) - meanX) * (*(b + i) - meanY); } return (coeff / (sizeA * sdX * sdY)); }

  • 学校の授業で3Dの描画を行っています。

    学校の授業で3Dの描画を行っています。 今回の課題は ベクトルP0P1とベクトルP1P2の外積ベクトルを計算せよ。    このベクトルをP0上に緑色で描け。     以下の外積関数を製作すること。 Hint for(i=0;i<3;i++) v0[i]=p1[i]-p0[i]; for(i=0;i<3;i++) v1[i]=p2[i]-p1[i]; gaiseki(v0, v1, v2); for(i=0;i<3;i++) p3[i]=p0[i]+v2[i]; void gaiseki(double a[], double b[], double c[]) { c[0]=a[1]*b[2]-a[2]*b[1]; c[1]=-a[0]*b[2]+a[2]*b[0]; c[2]=a[0]*b[1]-a[1]*b[0]; } というものでした。 私の書いたプログラムは以下の通りですが、33,34,36行目に構文のエラーが出てしまいます。 原因はなんなのでしょうか。 よろしくお願い致します。 /* 3Dシステムデザイン  ベクトルの外積 */ #include <sfcgl.h> #include <math.h> double p0[3]={-1.0,-1.0,0.}; double p1[3]={1.3,-1.0,0.}; double p2[3]={1.1,1.1,0.}; double xr=0.; double yr=0.; double p3[3]={0,0,0.}; double v0[3]={0,0,0.}; double v1[3]={0,0,0.}; double v2[3]={0,0,0.}; void gaiseki(double a[], double b[], double c[]) { c[0]=(a[1]*b[2])-(a[2]*b[1]); c[1]=(-a[0]*b[2])+(a[2]*b[0]); c[2]=(a[0]*b[1])-(a[1]*b[0]); } void display() { BGColor(255,255,255); WireColor(0,0,0); LineWidth(2); SGBeginEdit(); Rotate(xr,1,0,0); Rotate(yr,0,1,0); double i=0; for(i=0;i<3;i=i+1){ v0[%f]=p1[%f]-p0[%f];} //ここと// for(i=0;i<3;i=i+1){ v1[%f]=p2[%f]-p1[%f];} //ここと// gaiseki(v0, v1, v2); for(i=0;i<3;i=i+1){ p3[%f]=p0[%f]+v2[%f];} //ここ// DrawLine(p0[0],p0[1],p0[2],p1[0],p1[1],p1[2]); DrawLine(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2]); DrawLine(p2[0],p2[1],p2[2],p0[0],p0[1],p0[2]); WireColor(0,255,0); DrawLine(p0[0],p0[1],p0[2],p3[0],p3[1],p3[2]); SGEndEdit(); SGSwapFrames(); } void key(unsigned char c, int x, int y) { if(c=='x') xr+=5.; if(c=='y') yr+=5.; if(c=='a') p2[2]+=0.2; if(c=='b') p2[2]-=0.2; SGPostRedisplay(); } int main(int argc, char** argv) { SGInit(argc, argv); SGOpenWindow(50,50,600,600); SGSetViewPoint(0,0,5); SGSetDisplay(display); SGKeyBoard(key); SGCallBack(); return 0; }

  • C++ の質問です

    vector a の中に 1 4 9 16 vector b の中に 4 7 9 9 11 が入っていて 新しい vector c の中に 1 4 4 7 9 9 9 11 16 のように小さい順に並べたいのですが、 どのようなforloop をかいたら良いのでしょうか?? アドバイスください。。 つなげることしか出来ないです。。。 vector<int> mergeSorted(const vector<int>& a, const vector<int>& b) { int n = a.size(); int m = b.size(); vector<int> c(n + m); int i; for (i = 0; i < n; i++) c[i] = a[i]; for (i = 0; i < m; i++) c[n + i] = b[i]; return c; } sort() を使ってはいけないという条件です。 なにか、アイディアありましたら、お願いいたします、、

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

    座標を表すクラスとして 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

専門家に質問してみよう