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

このQ&Aのポイント
  • 質問:[]演算子のオーバーロードでつまづきました。
  • 代入文で左辺、右辺、両方ともに[]演算子を使う場合、int &operator[](int i)のようにして、戻り値を参照型にしています。
  • main関数内で、ob1[2]=ob2[2];のようにすると、左辺(ob1)にちゃんと代入されています。
回答を見る
  • ベストアンサー

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

[]演算子のオーバーロードでつまづきました。 代入文で左辺、右辺、両方ともに[]演算子を使う場合 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)を代入しているのでしょうか?

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

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

参照というのは、参照先を設定できるのは初期化時のみです。そこがポインタとは異なるところです。 今回の場合、右辺は参照型ですが、実際に左辺に代入されるのは参照先の値になります。

tattin894
質問者

補足

まず、main関数内のob1[2]という文によってoperator[]関数が呼び出され、return a[i];で戻り値として、参照型のa[i]が返され、main関数内のob[2]がこの戻り値と置き換わり、次にob2[2]という文が解釈され、またoperator[]関数が呼び出され、参照型のa[i]に置き換わる?そしてob1[2]=ob2[2]の=が評価され、 a[i](ob1側)にa[i](ob2側)が代入される? ↑があってるとしてたら、参照型は何に初期化されているのでしょうか? 戻り値がob1[2]と置き換わる時に、↓のことをやっているのと同じことなのでしょうか? int &a[i]; a[i]=ob1[2]; 違うとおもいますが。

その他の回答 (1)

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

> ↑があってるとしてたら、参照型は何に初期化されているのでしょうか? 参照型はa[i]に初期化されます。 C++では引数を渡したり、返却値を渡すというのは、仮引数や返却値を初期化するということになります。 > 戻り値がob1[2]と置き換わる時に、↓のことをやっているのと同じことなのでしょうか? > int &a[i]; > a[i]=ob1[2]; > 違うとおもいますが。 違います。ob1[2]=ob2[2];を擬似コードで書くと、 int& __r2 = ob2.a[2]; int& __r1 = ob1.a[2]; __r1 = __r2; という具合です。 参照では動作が見えにくいのであれば、ポインタを使って、 int* __r2 = &ob2.a[2]; int* __r1 = &ob1.a[2]; *__r1 = *__r2; と書き直せばわかっていただけるのではないかと思います。

関連するQ&A

  • 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; } どなたか答えて頂けると有難いです。

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

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

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

    こんにちは。質問させてください。 現在下記のような処理(main関数でやっているような処理)を実現させたいのですが、うまくコンパイルできません。 #include <iostream> class Test { public:   void TestFunc()   {     std::cout << "TestFunc" << std::endl;   } }; class AllowOverLoad { public:   Test* operator ->()   {     return new Test;   } }; int main() {   void ( Test::*lpTestFunc )() = &Test::TestFunc;   AllowOverLoad overload;   ( overload->*lpTestFunc )(); } 主なエラーは error C2296: '->*' : 無効です。左オペランドには型 'AllowOverLoad' が指定されています。 です。 おそらくこの問題を解決するにはAllowOverLoadに->*演算子をオーバーロードしなくてはいけないと思うのですが、->*演算子のオーバーロード方法がいまいちよくわかりません。 いい文献やHPも見つけられなかったので質問させていただきました。 /* 現在、本番のコーディングでは暗黙的なキャストを禁止しているのでAllowOverLoadクラスに暗黙的にTest*型にキャストするような処理はなしの方向で、あくまで->*演算子のオーバーロードということでお願いします。 Microsoft WindowsXP Professional Edition VisualStudio 2008 AcademicEdition */ よろしくお願いします。

  • 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#のインクリメント演算子のオーバーロード(前置きと後置き)

    インクリメント演算子をオーバーロードして、後置きインクリメントの場合に戻り値が演算前の結果を返すようにする方法はありませんか? class Sample {  public int x;  public int y;  public Sample(int x, int y)  {   this.x = x;   this.y = y;  }  public override string ToString()  {   return base.ToString() + " - x = " + x + ", y = " + y;  }  public static Sample operator ++()  {   x++; y++;   return this;  } } class EntryPoint {  public static void Main()  {   Sample sample = new Sample(1, 2);   // 「Sample - x = 2, y = 3」で、期待通り   Console.WriteLine(++sample);   // 「Sample - x = 3, y = 4」で、期待したのはインクリメントされる前の値である「「Sample - x = 2, y = 3」   Console.WriteLine(sample++);  } }

  • 演算子オーバーロードのプログラムで

    今、C++でテンプレートクラスや演算子オーバーロードを使ったプログラムの練習をしているのですが、どうしてもうまく動かなく質問させてもらうことにしました。 大まかに言えば、int型のvalueを持ったDataというクラスを用意し、演算子+と-のオーバーロードによって、クラスの足し算引き算を可能にしよう。ということなのですが、 それぞれのオーバーロードした演算子ともに、addSubtractという+と-両方に対応した関数を呼ぶことで使おうと思っています。 コードは以下のようになっています。 1 #include <iostream> 2 3 using namespace std; 4 5 template<class Comparable> 6 class Data { 7  public: 8   Data(){value = 0;} 9   Data(int i){value = i;} 10   int value; 11   Data<Comparable> operator+(const Data<Comparable> &); 12   Data<Comparable> operator-(const Data<Comparable> &); 13   Data<Comparable> Data<Comparable>::addSubtract(const Data<Comparable> & rhs, int sign); 14 }; 15 16 template<class Comparable> 17 Data<Comparable> Data<Comparable>::addSubtract(const 18 Data<Comparable> & rhs, int sign) { 18   int value1=this->value; 19   int value2=rhs.value; 20   Data<int> result(value1+(sign*value2)); 21   return result; 22 } 23 24 template<class Comparable > 25 Data<Comparable> Data<Comparable>::operator+(const Data<Comparable> & rhs) { 26   return addSubtract(&rhs, 1); 27 } 28 29 template<class Comparable > 30 Data<Comparable> Data<Comparable>::operator-(const 31 Data<Comparable> & rhs) { 31   return addSubtract(&rhs, -1); 32 } 33 34 int main() { 35   Data<int> matrix1(2); 36   Data<int> matrix2(1); 37   cout<<"data1:"<<matrix1.value<<endl; 38   cout<<"data2:"<<matrix2.value<<endl; 39 40   Data<int> result1 = matrix1+matrix2; 41   cout<<"data1+data2"<<result1.value<<endl; 42 43   Data<int> result = matrix1-matrix2; 44   cout<<"data1-data2"<<result2.value<<endl; 45 } このコードを実行したところ、以下のようなエラーメッセージが表示されて動かすことができません。 add.cpp:41: instantiated from here add.cpp:26: error: invalid conversion from `const Data<int>*' to `int' add.cpp:26: error: initializing argument 1 of Data<Comparable>::Data(int) [with Comparable = int]' アドバイスをいただけるとありがたいです。

  • c++でのインクリメント演算子++のオーバーロード

    C++学習者です。 たまたま手に入れた英語の教本に沿って勉強していますが、インクリメント演算子++のオーバーロードのサンプルコードで疑問に思ったことがあります。 それは日付を管理するためのDate というクラスの中に定義されている2つの関数です。 ひとつは日付を一日増やすためのインクリメント演算子++のオーバーロード関数(operator++)と、もう一つはその中で使われているプライベート関数(helpIncrement) です。 私の疑問は、このhelpIncrement()関数の定義の中でさらに、今まさに定義しようとしているインクリメント演算子++が使われているということです。つまりまだ定義し終わっていない演算子を使ってhelpIncrement()関数を定義しようとしているのですが、こんなことをして矛盾は起きないのでしょうか?コンパイルエラーにはならないのでしょうか? それらの関数のコードを下にコピーしてあります。 詳しい方がいらっしゃいましたら、どうぞよろしくお答えください。 Date &Date::operator++() { helpIncrement(); return *this; } void Date::helpIncrement() { if(!endOfMonth(day)) ++day; else if(month < 12 ){ ++month; day=1; } else[ ++year; month=1; day=1; }

  • 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 */

  • 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も確実にオーバーロードできる方法を ご存知のかた、お教え願います。

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

    delete演算子オーバーロードする際、 デストラクタが呼び出される困っています。 例えば、 void* operator new(size_t size, const char* filename , int line , const char* funcname ); とnew演算子をグローバル定義します。 すると、意図通りnew演算子がCallされ、対応するコントラクタも 問題なくCallされます。 そして、上記new定義にペアとなるdelete演算子もグローバル定義します。 void operator delete(void* pMem, const char* filename , int line , const char* funcname ); 通常どおりdeleteで呼び出してしまうと、標準のdeleteがcallされてしまうため、 #define MYELETE(s) operator delete( (void*)(s) , __FILE__ , __LINE__ , __FUNCTION__ ) 上記のようなカスタムマクロを定義してCallしています。 オーバーロード定義されたアドレスがCallされるところまで、 意図通りなのですが、肝心のデストラクタがCallされません。 型が判明している場合、 単体でデストラクタを明示的に呼び出すことはできますが、 任意のポインタのデストラクタを明示的に呼び出す方法は ありますでしょうか?

専門家に質問してみよう