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

このQ&Aのポイント
  • C#における++演算子のオーバーロードについて詳しく説明してください。
  • ++演算子のオーバーロード関数の実装が一つなのに前置インクリメントと後置インクリメントが適切に行われています。どのようなカラクリで実行されているのでしょうか?
  • C#の++演算子のオーバーロードについての記事を読んでみましたが、理解できませんでした。詳しく教えてください。
回答を見る
  • ベストアンサー

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 ================================================================ ++演算子のオーバーロード関数の実装が一つなのに 前置インクリメントと後置インクリメントが適切に行われています。 二つのインクリメントが行われるときに同じメソッドが 呼び出されていると思うのですが、同一の実装で、振る舞いが 異なるのは、なぜなのでしょうか?どのようなカラクリで 実行されているのでしょうか?全くわかりません。どなたか 教えてください。よろしくお願いします。

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

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

コード2の形式では面白くないですね なぜなら ++(--)の実装を変えてしまっているからです ++の前置き演算子の場合 引数の内容を保存してから 演算子メソッドが呼び出されます そのパラメータであるxは参照なのでこれを操作して変更してしまうと呼び出しもとのオブジェクトを操作することになってしまいます したがって ++tとしても t++としても加算された結果が式の値になってしまうのだろうと思います

__tanpopo__
質問者

お礼

redfox63 様へ ご回答ありがとうございました。 大変参考になりました。

その他の回答 (1)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

++演算子の 前置と後置での動作と異なるといったことですか? 期待した結果はどのような物なのでしょう 正常に機能しているように見えますが ・・・ 最初の t++は 後置きなのでtの値がWrite参照されてから加算された新しいclass Testオブジェクトが代入されますので 初期値の0が表示されます ++tは前置きなので加算処理実行されて新しいclass Testオブジェクトが代入されたオブジェクトを参照します

__tanpopo__
質問者

補足

redfox63 様へ 早速のご回答ありがとうございました。 質問の主旨がうまく伝わらなくてすみませんでした。 質問したいことを具体的に申しますと、++演算子を 次のようにオーバーロードして実行しますと、 === コード1==================================================== public static Test operator ++(Test t) { Test result = new Test(t.Num + 1); return result; } ================================================================ 後置きの実行結果が当初の質問にあります実行結果のように0に なるのに対して、++演算子を次のようにオーバーロードしますと 後置きの実行結果が、1になってしまいます。 === コード2 =================================================== public static Test operator ++(Test t) { t.Num++; return t; } =============================================================== どうして、コード2のように実装すると、後置きの演算結果が1になる のかがわからないのです。その原因を知りたいのですが、どうか ご回答お願いします。

関連するQ&A

  • 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++);  } }

  • 演算子のオーバーロードについて教えてください

    今あるクラスを作っていて class test { // なんらかの実装 }; void main() {   test t;   if( t )     return; } の「if( t )」の部分を実装したいのですがいまいち方法がわかりません。 「if( !t )」は実装できたのですが「if( t )」の方法がいまいちです。 よろしくお願いします。

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

    こんにちは。質問させてください。 現在下記のような処理(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++学習者です。 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++でのインクリメント演算子++のオーバーロード

    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#のプログラミングについて(基礎・・)

    どうしても エラーが出ます エラーの表示は 下のようなものなのですが、どういう意味かわかりません。 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)); } }

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

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

    今、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]' アドバイスをいただけるとありがたいです。

  • ジェネリックスに関して

    次のようなプログラムを書きました。 class A<T> {  public String display(T t) {   return t.toString();  } } public class Test extends A<String> {  public String display(Object o) { //ここでコンパイルエラー   return o.toString();  }  public static void main(String[] args) {   Test test = new Test();    test.display("hello, world");  } } 上で示した部分でコンパイルエラーが出ました。エラー内容は 名前の競合:型Testのメソッドdisplay(Object)は型A<T>のメソッドdisplay(T)と同じerasureを持っていますが、オーバーライドしません。 というものでした。この場合、 public class Test extends A<String> と、TがStringであることを明示しているので、このプログラムではdisplay(Object)はdisplay(T) をオーバーロードしているのではないのでしょうか。 もしくは、もしdisplay(Object)とdisplay(T)が同じerasureを持っているなら、それでオーバーライドしていることにはならないのでしょうか?

    • ベストアンサー
    • Java

専門家に質問してみよう