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

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

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

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

Q&A

解決済

1回答

1418閲覧

出力演算子をオーバーロードしたとき何が起こってる?実体はどこ?

yoshiki_iwasa

総合スコア23

C++

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

0グッド

0クリップ

投稿2020/10/31 08:17

### 質問概要

C++ の学習をしています。
出力演算子のオーバーロードを行った時、どうやってオーバーロードされたoperator<< が呼び出されているのかわかりません。 

質問詳細

以下に、クラスのヘッダファイル、クラスの実体を表す.cpp ファイル、実行用main.cpp ファイルを示します。

test.hpp

C++

1 2#ifndef DDE06408_CA21_4DBC_98E1_AF82BDCD6003 3#define DDE06408_CA21_4DBC_98E1_AF82BDCD6003 4 5#include <string> 6#include <iostream> 7 8class test 9{ 10private: 11 std::string name; 12 13public: 14 15 test(); 16 test(std::string name); 17   test &operator=(test const &); 18 std::string getName(); 19 ~test(); 20}; 21 22std::ostream &operator<<(std::ostream &os, test &obj); 23 24#endif /* DDE06408_CA21_4DBC_98E1_AF82BDCD6003 */ 25

test.cpp

C++

1#include "test.hpp" 2 3test::test(std::string name) : name(name) 4{ 5 6} 7 8 9test &test::operator=(test const & obj) 10{ 11 this->name = obj.name; 12 return (*this); 13} 14 15std::string test::getName() 16{ 17 return (name); 18} 19 20std::ostream &operator<<(std::ostream &os, test &obj) 21{ 22 os << "My name is " << test.getName() << std::endl; 23 return (os); 24} 25

main.cpp

C++

1 2#include "test.hpp" 3int main() 4{ 5 test one("TEST"); 6 test two("TEST2"); 7 8 std::cout << two; // 実行結果::My name is TEST2; 9 two.operator=(one); <- これはわかる。testクラスのメンバ関数をよびだしてるから。 10 std::cout << one; // 実行結果::My name is TEST; 11 std::cout << two; // 実行結果::My name is TEST; 12 13 14}

私が聞きたいことは、main.cpp において、std::ostream &operator<<(std::ostream &os, test &obj); はどうやって呼び出されているのか、とう言うことです。

クラス外に定義してあるのに、演算子のオーバーロードが正しく呼び出されるのはなぜでしょう。

std::ostream &operator<<(std::ostream &os, test &obj); が呼ばれるときは、実際はなにが起こっているのでしょうか?

two.operator=(one) <ー> two = one の様に他の表記の仕方もあるんでしょうか?

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

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

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

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

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

guest

回答1

0

ベストアンサー

今回のはただのフリー関数(メンバ関数ではない)の呼び出しと同じです。

cpp

1void foo() {} 2int main() 3{ 4 foo(); 5}

上の例でfooが呼べたのと同じ理屈です。単にグローバル名前空間から当該関数が探索され、呼び出されます。


さて、お示しの例をもうちょっといじってみます。

cpp

1namespace foo { 2class test 3{ 4private: 5 std::string name; 6 7public: 8 9 test(); 10 test(std::string name); 11   test &operator=(test const &); 12 std::string getName(); 13 ~test(); 14}; 15 16std::ostream &operator<<(std::ostream &os, test &obj); 17}

このときクラスtestfoo名前空間に所属しています。operator<<も同様です。

にもかかわらず、じつは以下のようなことが可能です。

cpp

1foo::test one("TEST"); 2std::cout << one;

これはもうすこしわかりやすい例でいうとこういうことです。

cpp

1namespace foo { 2struct bar {}; 3void hoge(const bar& b) 4{ 5 std::cout << "bar" << std::endl; 6} 7} 8int main() 9{ 10 hoge(foo::bar{}); 11}

関数hogefoo名前空間にあるのに、呼び出しのときにfoo::hoge(foo::bar{});のようになっていないのはなぜでしょうか。

Argument Dependent Look-upというものがあります。略してADLといいます。

Argument Dependent Lookup | 闇夜のC++

この働きによって呼び出せるわけです。

今回の質問からは外れますが、極めて近い状況なので紹介させていただきました。

投稿2020/10/31 08:57

yumetodo

総合スコア5852

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

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

yoshiki_iwasa

2020/10/31 10:47

なるほど! そうか、グローバル空間から勝手に該当するものを検索して引っ張ってきていたのですね すごいなぁ ありがとうございます。 追記で紹介してくださった、ADLの記事も大変参考になりました。確かに、なぜ std 名前空間にある '<<' が生で使えるのか疑問だったのでそれも解消できてよかったです!  最高っす!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問