質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1804閲覧

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

BeatStar

総合スコア4958

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/08/03 03:52

趣味で C++ ( better C ) をやっています。

演算子のオーバーロードについて質問があります。

クラスのメンバとして演算子をオーバーロードすることは不可能なのでしょうか?

一応可能ですが、なぜかうまくいかないことがあります。

例えば 関数オブジェクト ( ファンクタ? ) として扱えるように、

operator() をオーバーロードして

C++

1 2class CTest{ 3 public: 4 CTest(int id) : mId(id){} 5 ~CTest(){} 6 7 std::string operator()( const std::string str ){ 8 // 処理。ただ単に別のメンバ関数を呼び出すだけとか? 9 } 10 protected: 11 ... // メンバ関数があるとする 12 private: 13 ... // メンバ変数やメンバオブジェクトがあるとする 14};

のようにやるとします。

クラス定義やメンバ関数定義まではうまくいきます。( operator() も可能。 )

C++

1CTest test( 100 ); 2cout << test("hello") << endl;

のようにするとうまくいくのですが、

C++

1CTest* test = new CTest( 100 ); 2cout << test("hello") << endl; 3delete test;

のようにするとエラーが...

意訳すると

'test' を関数として使うことは出来ない

というエラーが出ます。

どこのサイトだったか 忘れましたが、

「oprator[] を定義されているとき、オブジェクト test での test[1] は test.operator と等価である」

のような文章 ( 出てくる演算子や細かい言い回し等は違う可能性もありますが。 ) を読んだことがあるので、

C++

1CTest* test = new CTest( 100 ); 2cout << test.operator()("hello") << endl; 3delete test;

としてみました。

すると普通にコンパイルが通りました。

自分ひとりでやっているので別に「このクラスは必ずnewじゃない方法で生成しろ。それで関数オブジェクトとして使用しろ。」

と自分なりの定義 ( 命名規則とかそういう感じで。 ) でやればいいかもしれませんが、

できれば newで生成するかどうかに関係なく そのまま使える方がいいのですが...

それって不可能なのでしょうか?

それともやり方 ( 引数である const std::string str を empty ("") にするとか、引数をすべてポインタにするとか ) があるのでしょうか?

[情報]
言語 : C/C++
コンパイラ: MinGW

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんにちは。

できれば newで生成するかどうかに関係なく そのまま使える方がいいのですが...

それって不可能なのでしょうか?

私も昔はそのように思っていました。しかし、C#で苦労した結果の結論は、ポインタとインスタンス実体は明確に区別するべきと思います。間違ったらエラーがでることは非常にありがたい仕掛けなのです。

C#はクラス型のインスタンスは通常はポインタで参照され、int型等の基本型も通常は実体が記録されます。そして、どちらも単なる代入文で設定します。
見た目、実体をコピーしているように見えてクラスの場合はポインタをコピーしているのです。
実体なのかポインタなのか気にせず同じ構文で記述できるため、気がつくとコピーするべき実体をコピーしないまま使っていて、実体を複数のクラスで共有してしまうことが稀にあります。そのバグ取りはたいへんでした。

ところで、

cout << test.operator()("hello") << endl;

は正しくは以下の通りですね?

cout << test->operator()("hello") << endl;

ちなみに次のようにもかける筈です。

cout << (*test)("hello") << endl;

投稿2017/08/03 04:07

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

CTest* test = new CTest( 100 );となっている以上、testポインタなので、何もせずにCTest::operator()が呼び出されることはありません。

なお、関数と関数オブジェクトを統一して扱いたい場合、std::functionというのが用意されていますので、それに代入すれば()だけで統一的に呼び出せます。

投稿2017/08/03 04:02

編集2017/08/03 04:08
maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問