teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

7

文章ちょっと修正

2017/03/20 07:10

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -1,4 +1,4 @@
1
- 結論
1
+ Chironianさんのコメントからの結論
2
2
 
3
3
  ```C++
4
4
  #include <iostream>

6

結論だけ書いた

2017/03/20 07:09

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -1,3 +1,50 @@
1
+ 結論
2
+
3
+ ```C++
4
+ #include <iostream>
5
+ class ComplexInt
6
+ {
7
+ private:
8
+ int real;
9
+ int imag;
10
+
11
+ public:
12
+ ComplexInt(int real, int imag = 0) : real(real), imag(imag) {}
13
+ friend ComplexInt operator+(const ComplexInt &x, const ComplexInt &y)
14
+ {
15
+ return ComplexInt(x.real + y.real, x.imag + y.imag);
16
+ }
17
+ friend std::ostream &operator<<(std::ostream &os, const ComplexInt &ci)
18
+ {
19
+ os << ci.real;
20
+ if (ci.imag >= 0) {
21
+ os << "+";
22
+ }
23
+ os << ci.imag << "i";
24
+ return os;
25
+ }
26
+ };
27
+
28
+
29
+ int main()
30
+ {
31
+ const ComplexInt a(2, 3);
32
+ const ComplexInt b(1, -5);
33
+ std::cout << a << std::endl;
34
+ std::cout << b << std::endl;
35
+ std::cout << (a + b) << std::endl;
36
+ std::cout << (a + 1) << std::endl;
37
+ std::cout << (1 + a) << std::endl;
38
+ return 0;
39
+ }
40
+ ```
41
+
42
+ 何も問題なし、以上。
43
+
44
+ 以下、駄文。
45
+
46
+ ---
47
+
1
48
  C++がだめな理由を考えました。
2
49
 
3
50
  ---

5

補足を追加

2017/03/20 07:05

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -239,8 +239,10 @@
239
239
 
240
240
  ぶっちゃけ、C++とScalaでは、単にScalaは暗黙の型変換とか使えば、実装が少なくて済むので楽だよね、程度しか無いと思います。ただ、C++の方が細かく実装できる分、コストがー、コストがー、と言っている深淵を覗くことが大好きな人達には好まれるでしょう。
241
241
 
242
- C++で何か嫌だと思う点の一つは、メンバー関数として実装できないことだと思います。オブジェクト指向原理主義者からみると、メソッドでない奴は駄目な奴だと勘違いしているのかも知れません。Scalaの暗黙の型変換もさほど変わらないと思うのですが、objectのメソッドだからいいとか言い出すのでしょうか…。
242
+ C++で何か嫌だと思う点の一つは、メンバー関数として実装できないことだと思います。オブジェクト指向原理主義者からみると、メソッドでない奴は駄目な奴だと勘違いしているのかも知れません。Scalaの暗黙の型変換もさほど変わらないと思うのですが、objectのメソッドだからいいとか言い出すのでしょうか…。
243
243
 
244
+ ※ friendsだとできるそうです。追記しています。
245
+
244
246
  あと、たぶん、何か嫌だと思ってしまうのは、標準型に新たなメンバー関数を追加しているように見えると言うことではないでしょうか。じゃあ、ScalaやRubyはどうなのかというと、確かに、元々の標準型に何かを追加している訳ではありませんが、一歩離れれば、やっていることはさほどかわりありません。やり方が違うだけで目くじら立てるのはどうなのかとは思ってしまいます。
245
247
 
246
248
  最後にHaskellを見てみましょう。Haskellの`a + b`は`(+)(a)(b)`です。他の関数と同じようにオーバーロードできます。オブジェクト指向なんかにして、無理にメソッドとかメンバー関数とか、そんなことをするより、全部関数にしておけば良かったのかも知れません。

4

崩れてた

2017/03/20 04:26

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -231,6 +231,7 @@
231
231
  std::cout << (1 + a) << std::endl;
232
232
  return 0;
233
233
  }
234
+ ```
234
235
 
235
236
  では、これで一安心だねっていうかと思うと、ちょっと使っただけで、グローバルに動作を影響を与えています。あ、Scalaと暗黙の型変換を検索するところと検索の仕方だけは同じ所に戻っただけのようです。
236
237
 

3

C\+\+フレンズ

2017/03/20 04:17

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -242,4 +242,65 @@
242
242
 
243
243
  あと、たぶん、何か嫌だと思ってしまうのは、標準型に新たなメンバー関数を追加しているように見えると言うことではないでしょうか。じゃあ、ScalaやRubyはどうなのかというと、確かに、元々の標準型に何かを追加している訳ではありませんが、一歩離れれば、やっていることはさほどかわりありません。やり方が違うだけで目くじら立てるのはどうなのかとは思ってしまいます。
244
244
 
245
- 最後にHaskellを見てみましょう。Haskellの`a + b`は`(+)(a)(b)`です。他の関数と同じようにオーバーロードできます。オブジェクト指向なんかにして、無理にメソッドとかメンバー関数とか、そんなことをするより、全部関数にしておけば良かったのかも知れません。
245
+ 最後にHaskellを見てみましょう。Haskellの`a + b`は`(+)(a)(b)`です。他の関数と同じようにオーバーロードできます。オブジェクト指向なんかにして、無理にメソッドとかメンバー関数とか、そんなことをするより、全部関数にしておけば良かったのかも知れません。
246
+
247
+ ---
248
+
249
+ 君はC++が得意なフレンズなんだね。
250
+
251
+ ```C++
252
+ #include <iostream>
253
+ class ComplexInt
254
+ {
255
+ private:
256
+ int real;
257
+ int imag;
258
+
259
+ public:
260
+ ComplexInt(int real, int imag) : real(real), imag(imag) {}
261
+ ComplexInt operator+(const ComplexInt &other) const
262
+ {
263
+ return ComplexInt(real + other.real, imag + other.imag);
264
+ }
265
+ ComplexInt operator+(int other) const
266
+ {
267
+ return ComplexInt(real + other, imag);
268
+ }
269
+ std::string toString() const
270
+ {
271
+ std::string str("");
272
+ str += std::to_string(real);
273
+ if (imag >= 0) {
274
+ str += "+";
275
+ }
276
+ str += std::to_string(imag) += "i";
277
+ return str;
278
+ }
279
+ int getReal() const { return real; }
280
+ int getImag() const { return imag; }
281
+ friend std::ostream &operator<<(std::ostream &os, const ComplexInt &ci)
282
+ {
283
+ os << ci.toString();
284
+ return os;
285
+ }
286
+ friend ComplexInt operator+(int x, const ComplexInt &y)
287
+ {
288
+ return ComplexInt(x, 0) + y;
289
+ }
290
+ };
291
+
292
+
293
+ int main()
294
+ {
295
+ const ComplexInt a(2, 3);
296
+ const ComplexInt b(1, -5);
297
+ std::cout << a << std::endl;
298
+ std::cout << b << std::endl;
299
+ std::cout << (a + b) << std::endl;
300
+ std::cout << (a + 1) << std::endl;
301
+ std::cout << (1 + a) << std::endl;
302
+ return 0;
303
+ }
304
+ ```
305
+
306
+ メンバー関数にできたけど、これこれで、ありなんだそうです。C++書くのつかれた。

2

名前空間を追加

2017/03/20 04:15

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -61,8 +61,10 @@
61
61
 
62
62
  Scalaは演算子がメソッドだ!と言っていますが、C++も演算子はメソッド相当であるメンバー関数として定義できます。その部分に違いはありません。しかし、メンバー関数として定義した場合は、`1 + a`のような整数が前に来るような足し算には対応できません。そのため、`ComplexInt operator+(int x, const ComplexInt &y)`というグローバル関数を別途定義する必要が出てきます。
63
63
 
64
- グローバル空間を汚すことは**行儀が悪いコード**と言われます。しかし、C++の演算子オーバーロードではグローバル関数として定義せざるをえない場合があります。
64
+ グローバル空間を汚すことは**行儀が悪いコード**と言われます(つまり、Cだと関数一個も作れないと言うこと)。しかし、C++の演算子オーバーロードではグローバル関数として定義せざるをえない場合があります
65
65
 
66
+ ※ 名前空間は汚す必要ない!って話なので、名前空間を汚さないの後から追記しています。
67
+
66
68
  対して、Scalaでは左辺も含めた暗黙の型変換を定義できるため、次のようになります。
67
69
 
68
70
  ```Scala
@@ -117,7 +119,7 @@
117
119
  }
118
120
  ```
119
121
 
120
- ぱっと、C++とは違ってグローバル関数を使ってないですので、グローバルを汚すと言うことはしていないように思えます。しかし、暗黙の型変換も暗黙のクラスもグローバルに影響を与えています。ただ、足し算という処理は一つにまとめることができますので、C++よりはマシであると言えるのではないでしょうか。
122
+ ぱっと、C++とは違ってグローバル関数を使ってないですので、グローバルを汚すと言うことはしていないように思えます。しかし、暗黙の型変換も暗黙のクラスもグローバルに影響を与えています。**どっちにしろグローバルを汚します。**ただ、足し算という処理は一つにまとめることができますので、C++よりはマシであると言えるのではないでしょうか。
121
123
 
122
124
  おまけで、Rubyを見てみましょう。
123
125
 
@@ -168,4 +170,76 @@
168
170
 
169
171
  RubyにはNumeric#coerceという仕組みがあります。これは、自分が知らない型なら相手のcoerceを呼び出して型をあわせようとする動作です。Numeric、つまり、数値をあらわす型のみですが、この仕組みにより、任意の数値のような型を追加することができます。実際にBigDecimal(任意精度十進数小数点数)やMatrix(行列)ではこの仕組みを使って、通常のInteger(整数)と足し算などができるようになっています。
170
172
 
171
- この仕組みの利点は、グローバルを汚さないということです。他の型と動作が変わったわけではありません。しかし、欠点として、もともとの定義がcoerceを考慮していなければなりません。実質使えるのは数値のみです。
173
+ この仕組みの利点は、グローバルを汚さないということです。他の型と動作が変わったわけではありません。しかし、欠点として、もともとの定義がcoerceを考慮していなければなりません。実質使えるのは数値のみです。
174
+
175
+ ---
176
+
177
+ 名前空間を汚さなくても大丈夫だそうです。
178
+
179
+ ```C++
180
+ #include <iostream>
181
+ namespace ci {
182
+ class ComplexInt
183
+ {
184
+ private:
185
+ int real;
186
+ int imag;
187
+
188
+ public:
189
+ ComplexInt(int real, int imag) : real(real), imag(imag) {}
190
+ ComplexInt operator+(const ComplexInt &other) const
191
+ {
192
+ return ComplexInt(real + other.real, imag + other.imag);
193
+ }
194
+ ComplexInt operator+(int other) const
195
+ {
196
+ return ComplexInt(real + other, imag);
197
+ }
198
+ std::string toString() const
199
+ {
200
+ std::string str("");
201
+ str += std::to_string(real);
202
+ if (imag >= 0) {
203
+ str += "+";
204
+ }
205
+ str += std::to_string(imag) += "i";
206
+ return str;
207
+ }
208
+ int getReal() const { return real; }
209
+ int getImag() const { return imag; }
210
+ };
211
+
212
+ std::ostream &operator<<(std::ostream &os, const ComplexInt &ci)
213
+ {
214
+ os << ci.toString();
215
+ return os;
216
+ }
217
+ ComplexInt operator+(int x, const ComplexInt &y)
218
+ {
219
+ return ComplexInt(x, 0) + y;
220
+ }
221
+ }
222
+
223
+ int main()
224
+ {
225
+ const ci::ComplexInt a(2, 3);
226
+ const ci::ComplexInt b(1, -5);
227
+ std::cout << a << std::endl;
228
+ std::cout << b << std::endl;
229
+ std::cout << (a + b) << std::endl;
230
+ std::cout << (a + 1) << std::endl;
231
+ std::cout << (1 + a) << std::endl;
232
+ return 0;
233
+ }
234
+
235
+ では、これで一安心だねっていうかと思うと、ちょっと使っただけで、グローバルに動作を影響を与えています。あ、Scalaと暗黙の型変換を検索するところと検索の仕方だけは同じ所に戻っただけのようです。
236
+
237
+ ---
238
+
239
+ ぶっちゃけ、C++とScalaでは、単にScalaは暗黙の型変換とか使えば、実装が少なくて済むので楽だよね、程度しか無いと思います。ただ、C++の方が細かく実装できる分、コストがー、コストがー、と言っている深淵を覗くことが大好きな人達には好まれるでしょう。
240
+
241
+ C++で何か嫌だと思う点の一つは、メンバー関数として実装できないことだと思います。オブジェクト指向原理主義者からみると、メソッドでない奴は駄目な奴だと勘違いしているのかも知れません。Scalaの暗黙の型変換もさほど変わらないと思うのですが、objectのメソッドだからいいとか言い出すのでしょうか…。
242
+
243
+ あと、たぶん、何か嫌だと思ってしまうのは、標準型に新たなメンバー関数を追加しているように見えると言うことではないでしょうか。じゃあ、ScalaやRubyはどうなのかというと、確かに、元々の標準型に何かを追加している訳ではありませんが、一歩離れれば、やっていることはさほどかわりありません。やり方が違うだけで目くじら立てるのはどうなのかとは思ってしまいます。
244
+
245
+ 最後にHaskellを見てみましょう。Haskellの`a + b`は`(+)(a)(b)`です。他の関数と同じようにオーバーロードできます。オブジェクト指向なんかにして、無理にメソッドとかメンバー関数とか、そんなことをするより、全部関数にしておけば良かったのかも知れません。

1

左辺!左辺!左辺!

2017/03/20 04:05

投稿

raccy
raccy

スコア21784

answer CHANGED
@@ -63,7 +63,7 @@
63
63
 
64
64
  グローバル空間を汚すことは**行儀が悪いコード**と言われます。しかし、C++の演算子オーバーロードではグローバル関数として定義せざるをえない場合があります。
65
65
 
66
- 対して、Scalaでは暗黙の型変換を定義できるため、次のようになります。
66
+ 対して、Scalaでは左辺も含めた暗黙の型変換を定義できるため、次のようになります。
67
67
 
68
68
  ```Scala
69
69
  class ComplexInt(val real: Int, val imag: Int) {