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

このQ&Aのポイント
  • 挿入演算子<<をオーバーロードする際、第1引数をconst ostream& outとするとコンパイルエラーが発生する。
  • constを修飾すると、outの状態を変更できないことを意味している。
  • コンパイルエラーが発生する理由は、Visual C++ 2005 Express Editionの仕様によるものである。
回答を見る
  • ベストアンサー

挿入演算子<<をオーバーロードについて

はじめまして。 質問があります。 class Foo { ・・・ // NG friend ostream& operator<< (const ostream& out , Foo& c); ・・・ }; 挿入演算子<<をオーバーロードするとき、挿入演算子関数の第1引数をconst ostream& outのようにconstを修飾するとコンパイルエラーに なります。私としては、outの状態を変更したくないという意味 で修飾したのですが、なぜコンパイルエラーになるのかがわかりません。どうかご教授お願いします。 現在、Visual C++ 2005 Express Editionを使用しています。

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

  • ベストアンサー
  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.4

>コメントアウトして実行してみたところ、コンパイルエラーが >でなくなりました。outはやはり、変更されているのですね。 蛇足ですが、コンパイラは out が変更されるかどうかをチェックしているのではなくて、あくまでその宣言に const 指定がないことを見てエラーとしています。 したがって、本当は内容を変更していない hoge(ostream& out) を operator<<(const ostream& out, Foo& c) の実装中に使ってもエラーになります。 逆に、Foo の定義されたネームスペースの中で operator<<(const ostream& out, const std::string&) 等が定義されていれば、そっちを使うのでエラーにはなりません。

re-entry
質問者

補足

koko_u_様へ 連絡が遅れました。すみませんでした。 ご回答ありがとうございます。 コンパイラがoutが変更されているかどうかをチェックしているのではなく、宣言の形式だけを見てエラーとしていることがわかり、そういう ものなのだと、理解しています。 ただ、 >逆に、Foo の定義されたネームスペースの中で operator<<(const ostream& out, const std::string&) 等が定義されていれば、そっちを使うのでエラーにはなりません。 を動作確認しようと思い、サンプルコード全体をを単純に namespace foo {}等で囲ってみてもエラーが出てしまいます。 多分私自身勘違いをしていると思いますが、具体的にどういうことなの かご教授お願いします。別件で改めて質問をさせていただいても かまいません。(本質問は良回答とさせていただきます。)

その他の回答 (4)

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.5

>を動作確認しようと思い、サンプルコード全体をを単純に >namespace foo {}等で囲ってみてもエラーが出てしまいます。 じゃあ、多分オレが間違えてる。 別の質問を立てて、ほんとに分っている人にアドバイスしてもらった方がいいでしょう。

re-entry
質問者

お礼

koko_u_様へ ご回答ありがとうございました。 いろいろとアドバイスしていただきまして、 感謝しております。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.3

>コンパイラがostream& outを使用しているのが原因なのですね。 ちがう。orz 「re-entry さんが」std::operator<<(ostream& out, ... ) を使っているからです。 コンパイラは親切にも out が変更されるよと教えてくれているのです。

re-entry
質問者

お礼

koko_u様へ ご回答ありがとうございました。 勘違いを指摘してくださいまして、感謝しております。 挿入演算子関数内のすべての定義内容を コメントアウトして実行してみたところ、コンパイルエラーが でなくなりました。outはやはり、変更されているのですね。 勉強になりました。 ありがとうございました。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.2

>確かにoperator<<(const ostream &out,Car &c)の定義内容は >outオブジェクトの状態を変更する記述がないように思えるのですが、 >間違いでしょうか? コンパイラから見ると out << "ナンバー=" << c.num << ":" << "ガソリン=" << c.gas << endl; で std::operator<<(ostream& out, ... ) を使用しているので、out が変更されない保証がないとしてコンパイルエラーになります。 また、実際 out に文字列を書き込めば、ストリームの状態が変更されるので const にはできません。

re-entry
質問者

お礼

koko_u_様へ ご回答ありがとうございました。 コンパイラがostream& outを使用しているのが原因なのですね。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

関数の中身がわからんので何とも言えませんが、 ostream を何らか操作すれば内容はかわると思いますが。

re-entry
質問者

補足

koko_u_様へ ご回答ありがとうございました。 サンプルを提示するべきでした。すみません。 ---------------------------------------------------------------- #include <iostream> using namespace std; class Car { private: int num; double gas; public: Car(int num,double gas); friend void operator<<(const ostream &out,Car &c); }; Car::Car(int num, double gas) { this->num = num; this->gas = gas; } void operator<<(const ostream &out,Car &c) { out << "ナンバー=" << c.num << ":" << "ガソリン=" << c.gas << endl; } int main() { Car *car = new Car(15, 26.7); cout << *car; return (0); } ---------------------------------------------------------------- 確かにoperator<<(const ostream &out,Car &c)の定義内容はoutオブジェクトの状態を変更する記述がないように思えるのですが、間違いでしょうか?どうかよろしくお願いします。

関連するQ&A

  • 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++]

    入出力演算子を使ったコードを書いているのですが わからないところがあるので教えてください。 friend std::ostream& operator <<( std::ostream& out, const Box can ); friend std::istream& operator >>( std::istream& in, Box & can ); friend std::ostream& operator <<( std::ostream& out, const Box * can ); friend std::istream& operator >>( std::istream& ins, Box * & can ); このうち上の二つの普通の演算子はちゃんと動いている のですが、下の二つはどのようにすればいいのかわかりません。 下のコードのようにポインタを使って入出力したいんですが・・・ Box * ptrCan = NULL; cout << ptrCan; ptrCan = &t; cout << ptrCan; cin >> ptrCan; cout << ptrCan;

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

    こんばんは。 C++言語の勉強をしています。 new演算子をオーバーロードしたいのですが、引数としてvoid*を渡したかったのですが、 エラーC2821が出力されてできませんでした。 エラー内容が第一引数がsize_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 */ よろしくお願いします。

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

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

  • 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++学習者です。Visual Studio 2015 を使っています。 入力演算子>> と出力演算子<<をオーバーロードする関数をfriend としてクラス定義の中に書きましたが、”メンバーではありません” というメッセージが出てきてコンパイルできません。 エラー番号はC2039です。 何回調べても原因がわからないので、詳しい方にお聞きしたいです。 どうかよろしくお願いいたします。 ヘッダーファイルと関数定義ファイル、クライアントプログラムと、エラーメッセージのコピーを張り付けてあります。 // クラスヘッダーファイル // class Array header #ifndef ARRAY1_H #define ARRAY1_H #include <iostream> using namespace std; class Array { // operator overloading as non-member functions friend ostream &operator<<(ostream &, const Array &); friend istream &operator>>(istream &, Array &); public: Array(int = 10); // constructor with default of 10 elements of array Array(const Array &); //copy constructor ~Array(); // destructor int getSize() const; // size of array // operator overloadings as member functions const Array &operator=(const Array &); // assignment bool operator==(const Array &) const; // check equality of two arrays // because both sides of the operator are constant, // this function must be constant too bool operator!=(const Array &right) const { // fully defined function in the header file like this one // will be made in-line function and save overhead time return !(*this == right); } int &operator[](int); // check subscript range for non-constant array const int &operator[](int) const; // check subscript range for constant array // remember we can only invoke constant function of a constant object // so if we want to check the subscript range of a constant object, we need // to use a constant member function of that object, that's why we need a // constant version of the same functionn as above operator[] private: int size; // size of array int *ptr; // pointer to the first element of the array // so ptr is the name of the array }; // end of class Array definition #endif // 関数定義ファイル // array1.cpp // member function definitions of class Array #include "stdafx.h" #include <iostream> #include <iomanip> using namespace std; using std::cout; #include <new> // for new and delete #include <cstdlib> // for exit() using std::exit; #include "array1.h" // >> , << 以外のオーバーロード関数は省略します // input operator overloading istream &Array::operator>>(istream &input, Array &a) { for (int i = 0; i < a.size; i++) input >> a.ptr[i]; return input; } // output operator overloading ostream &Array::operator<<(ostream &output, const Array &a) { int i; for (i = 0; i < a.size; i++) { output << setw(12) << a.ptr[i]; if ((i + 1) % 4 == 0) output << endl; } if (i % 4 != 0) output << endl; return output; } // クライアントプログラム // ConsoleApplication87.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #include <iostream> using namespace std; #include "array1.h" int main() { Array integers1(7); // 7 elements array Array integers2; // default 10 element array cout << "size of array integer1 is " << integers1.getSize() << endl; cout << "contents of integers1 after instantiation are :\n"; cout << integers1; cout << "---------------------------------------------\n"; cout << "size of array integers2 is " << integers2.getSize() << endl; cout << "contents of integers2 after instantiation are :\n"; cout << integers2; cout << "---------------------------------------------\n"; return 0; } // エラーメッセージ 1>------ ビルド開始: プロジェクト:ConsoleApplication87, 構成:Debug Win32 ------ 1> array1.cpp 1>c:\users\shiro\documents\visual studio 2015\projects\consoleapplication87\consoleapplication87\array1.cpp(96): error C2039: '>>': 'Array' のメンバーではありません。 1> c:\users\shiro\documents\visual studio 2015\projects\consoleapplication87\consoleapplication87\array1.h(9): note: 'Array' の宣言を確認してください 1>c:\users\shiro\documents\visual studio 2015\projects\consoleapplication87\consoleapplication87\array1.cpp(104): error C2039: '<<': 'Array' のメンバーではありません。 1> c:\users\shiro\documents\visual studio 2015\projects\consoleapplication87\consoleapplication87\array1.h(9): note: 'Array' の宣言を確認してください ========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

  • 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されません。 型が判明している場合、 単体でデストラクタを明示的に呼び出すことはできますが、 任意のポインタのデストラクタを明示的に呼び出す方法は ありますでしょうか?

  • フレンド関数を利用したオーバーロードでコンパイルエラー

    独習C++(第3版)で学習していますが、書籍通りに入力してもコンパイルエラーが出てしまい、困っております。 P.199 6.5.フレンド演算子関数の使用にあるソースコードをそのままコピーしただけです。 フレンド関数を利用し、演算子オーバーロードをすると、コンパイルエラーが発生してしまうようです。 (10): friend coord operator+(coord ob1,int i); C:\jsp\tools\samp13\XXXX.cpp(10) : fatal error C1001: 内部コンパイラ エラー (コンパイラ ファイル 'msc1.cpp', 行番号 1786) Visual C++ のサポート情報 コマンドを選択してください ヘルプ メニュー、 またはサポート情報のヘルプ ファイルを参照してください 少し検索したところVC++6.0だとバグで起こってしまうとのことですが、この状態からコンパイルエラーを無くすには何をしたらよいのでしょうか?

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

専門家に質問してみよう