C ++にはあるがJavaにはない言語機能を避けるべきですか?


110

プロジェクトの環境によってC ++の使用に制限されているとします。C ++にはあるがJavaにはないいくつかの言語機能(例えば、多重継承、演算子のオーバーロード)の使用を防ぐのは良いですか?

その理由は次のとおりです。

  1. JavaはC ++よりも新しいため、JavaがC ++の機能を提供しない場合、その機能は適切ではないことを意味するため、使用を避ける必要があります。
  2. C ++固有の機能(例:フレンド関数、多重継承)を備えたC ++コードは、C ++プログラマーのみが保守またはレビューできますが、JavaのようなC ++(C ++言語固有の機能なし)を記述するだけで、コードは両方によって保守またはレビューできますC ++およびJavaプログラマ。
  3. いつかJavaにコードを変換するように求められる場合があります
  4. 通常、C ++固有の機能を持たないコードの方が保守しやすい
  5. すべてのC ++言語固有の機能(例:多重継承)には、Javaで実装する代替手段が必要です。そうでない場合、設計パターンまたはコードアーキテクチャに問題があることを意味します。

本当?


7
提案を見れば、コーディング標準の作成について話していることになります。標準を作成し、それに従っているという事実が、実際に保守性を向上させるものです。
ブランディン

63
JavaコードもC ++言語にある機能に制限する必要がありますか?たとえば、Java volatile、パッケージプライベートクラスメンバアクセス、リフレクション/イントロスペクション、finally-blocks、チェック例外などを使用しないでください。質問全体はあまり意味がありません... C ++とJavaは表面的には似ていますが、最終的には非常に異なる言語です。
ハイド

5
人々が新機能を使用したくない場合、言語はどのように進化しますか?新しい機能の目的は、一般的な問題を解決することであなたの生活を楽にすることです。ユーザーが新しい機能を使用しない場合、誰もがそれらを実装する動機はありません。
マシュー

72
Javaが必要な場合は、Javaを使用します。C ++を使用する場合は、C ++構文を使用したJavaの恐ろしいねじれた模倣ではなく、C ++を使用してください。C ++を使用しますが、Javaの機能セットに制限すると、両方の世界で最悪の事態になります。
ジェリーコフィン

11
違いがどれほど速く噛みつくか(そして難しい)に驚くでしょう。 SomeObject a = previousObject;ない非常に JavaとC ++で異なるものを。Javaでは参照をコピーし、C ++ではオブジェクトをコピーします。Javaでは、変更aは以前のオブジェクトにも影響します。C ++では、2つの別個のオブジェクトがあります。
時計仕掛けミューズ

回答:


307

いいえ。これは悲惨でひどく見当違いです。

  • Java機能は、特に真空状態ではC ++機能よりも優れているとは言えません。
  • プログラマーが機能の使用方法を知らない場合、優れた開発者を訓練または雇用する。開発者をチームの最悪の人に制限することは、優秀な開発者を失う簡単な方法です。
  • ヤグニ。将来の問題の幽霊ではなく、今日のあなたの実際の問題を解決してください。

6
開発者が、通常は記述しない言語でコードをレビューすることについて、最近質問がありました。ここでの知恵はここに当てはまると思います:優れた開発者はあらゆる言語で多くの基本的な間違いを見つけますが、各言語には非常に多くの落とし穴があり、言語内の開発者がレビューを行うと最大限の利益が得られます。これは、C ++が「Java機能のみ」の場合にも当てはまります。
corsiKa

5
+1 2番目のポイントに加えて。OPは、使用する機能を決定するために「C ++ベストプラクティス」について時間をかけて読む必要があります。C ++についての私の最後の情報は、フレンド関数多重継承Bad Practicesと見なされるということです。以下のようなものテンプレート演算子のオーバーロードは、あなたが賢明にそれらを使用する場合私見グッドプラクティスです。
-some_coder

4
@some_coder:いつ、どこで、それを知ることです。ポリシーベースのプログラミングを行うとき、(おそらく複数の)ポリシークラスから継承して、ポリシークラスが機能するために必要なメンバーでホストクラスの構造を拡張します。それはちょうどそれがどのように機能するかです。また、operator<<( ostream &, T const & )通常はを介して実装されfriendます。...そうでない場合を除き、彼らは、良いアドバイスです:それは毛布の良い言語機能何についての声明、何悪いものだとの問題だ
DevSolar

142

構文が表面的に似ているように見えるからといって、2つの言語に互換性があることを意味するわけではありません。

1、4、5は本当に同じ質問です。

今、私はC ++のファンではありませんが、「C ++固有の機能を持たないコードは通常、保守性が高い」と言うのはばかげています。普遍的に「悪い」または「良い」機能である何かがあると本当に信じていますか?ある場合、純粋に良い言語が1つないのはなぜですか?いいえ、Javaは確かにその言語ではありません。JavaとC ++は役に立たないということですか?もちろん違います。

リーダーが、JavaではなくC#に移植することに決めた場合はどうなりますか?C#はオーバーライド演算子をサポートするだけでなく、デフォルトでもあります。たとえばのobj.Equals(obj2)代わりに人々に使用を要求する場合obj == obj2、人々は常に間違いを犯します。2つの言語の共通の特徴だけを守っても、異なる期待、異なる文化があります。if (myField == null)C ++のようなことをすれば、人々はあなたがすぐに初心者であることをすぐに知るでしょう。if (null == myField)C#で使用する場合、人々はあなたがまだC#ネイティブではないことに気付くでしょう。

プログラマーが習得しなければならない新しい機能を追加するだけでPascalのようなものに変更するのはなぜですか?ループさえないのに、なぜSQLのようなものを使用するのでしょうか?なぜ我々はこれまでに何か使用することになり、他の SQLは、ループを持っていないとすると、SQL以外のXはいますか?

C ++コードは確かに Javaプログラマーによって保守できません。このアイデアがどこで得られたのか理解できません-C ++をJavaとまったく同じように機能する機能だけに制限するとどうなるのでしょうか?メソッド呼び出しも、関数呼び出しも取得しません。繰り返しますが、両方の言語が中括弧を使用しているからといって、言語が何らかの形で互換性があるという意味ではありません。

Javaに似たC ++コードの変換は、何をしても非常にエラーが発生しやすくなります。違いが多すぎます。アプリケーションを別の言語で書き直す必要がある場合は、すべてをモジュール化する合理的な方法を検討してください。そうすれば、全体を壊すことなく部品を交換できます。しかし、最終的にはYAGNI-何をするにしても、コードを「Javaに変換する準備ができている」ようにするのに多大なコストがかかります。それは、機能の追加または改善に費やす時間である可能性が非常に高い時間です。

問題を解決するための異なるツールセットを提供するため、異なる言語を使用します。「どこでも」動作する実行可能ファイルが必要な場合は、Javaを使用してください。「どこでも」コンパイルするコードが必要な場合、C ++は正常に動作します。理解して解析しやすいコードが必要な場合は、LISPなどを使用してください。しかし、私はあなたに一つのことを伝えることができます-あなたが別の言語で書いているかのようにある言語でコードを書くことは常に間違いであり、あなたは苦しむでしょう。言うまでもなく、実際にC ++の人を雇うと、彼は「Javaに準拠した」コードを見た2番目の人を実行します。そして... Javaの男は同じことをするつもりです。C ++とJavaの両方を「知っている」としても、私は地獄のように走ります:)

私は実際に、あなたのように考えているように見えるPascal開発者によって書かれた(単純な)Cコードに取り組まなければなりませんでした。彼は#defines を使用してCを再定義し、Pascalのように見えるようにし、「BEGINは{に変換する」などの機能を備えています。結果はかなり予測可能でした-C開発者もPascal開発者も理解できないコードであり、C上のPascalの「抽象化」の漏れの結果であるバグでいっぱいです。PascalとCは、今日の観点からはほとんど同じです。C <-> C ++を使用することでさえ、はるかに大きな違いがあります。それは、C ++ <-> Javaのようなものに対するピーナッツです。


9
「理解しやすく解析しやすいコードが必要な場合は、LISPなどを使用してください。」私はそれに同意しません。Lispは解析するのは簡単ですが、まさにこれのためです-パーサーの知識とそれらを効果的に構築する背後にある原理がまだ初期段階にあったときに作成されたため、彼らは最もばかげて単純なものを打ちましたおそらく動作する可能性があります。現代言語の構文上の利点をあまり得られません。そのため、解析は簡単ですが、理解するのは簡単ではありません。人々がそれを「余分な括弧を失った」と呼ぶ理由があります。
メイソンウィーラー

9
@MasonWheelerそれは好みの問題です-CプログラマーはそれをLISPers:Pではなくそれと呼びました。括弧を数えます-典型的なC ++プログラムと同じくらい多くあります。本当の違いはそれらの位置(myFunc()(myFunc))であり、それには非常に正当な理由があります。LISPベースの言語は、特に数学/物理学の人々にとっては依然として非常に人気があります。主なことは、実際には、LISPy言語は現代のCスタイルのプログラマーにはあまり馴染みがないということですが、それを無視する理由はほとんどありません。Scheme、Clojure、そしてある程度までMLベースの言語(OCaml、F#...)は非常にLISPyです。
ルアーン

4
@Luaan LISPが物理学で人気がないことは確かです。この分野の2つの主要な言語は、FORTRANとC ++です。FORTRANは非常に多くの古いコードが記述されているため「人気」ですが、ほとんどすべての新しいプログラムはC ++で記述されています。研究物理学者として、私は一度もLISPプログラムに出会ったことはなく、聞いたことすらありません。それらが存在しないと言うわけではありませんが、言語は間違いなく人気があります。
ジェームズマッタ

4
@Luaanより多くのソフトウェア開発者が必要な場合とそうでない場合があります。CSの卒業生を増やす必要はありません。「構造エンジニアをもっと必要とするので、理論物理学の卒業生がもっと必要だ」と言っているようなものです。
マイルルーティング

4
@ user1717828それはタイプミスの楽しい影響を避けるためにだif (myField == null)ようにif (myField = null)うまくC / C ++をコンパイルします。これは、おそらくないあなたが意図したものを行います。一方、if (null = myField)定数に代入できないため、エラーがスローされます。
ブレリン

94

ご質問にお答えします。

  1. JavaがC ++の機能を提供しない場合は、その機能が適切ではないことを意味するため、使用しないようにする必要があります。

はい、Javaに存在しない機能は、ハードドライブ上の嫌悪感です。コードベースから焼き付ける必要があります。従わない人はられ、彼らの魂はRAIDの神々をなだめていました。

  1. C ++固有の機能(例:フレンド関数、多重継承)を備えたC ++コードは、C ++プログラマーのみが保守またはレビューできますが、JavaのようなC ++(C ++言語固有の機能なし)を記述するだけで、コードは両方によって保守またはレビューできますC ++およびJavaプログラマ。

疑わしい場合は、チームの最も能力の低いメンバーのコードを記述してください。コードは、書かれているよりもはるかに頻繁に読み取られます。また、できる限り賢いコードは、読むにはあまりにも賢いです。フロントデスクのスタッフが理解できないコードレビューは拒否する必要があります。支援するために、週末にVisual Basic 2.0でプログラミングする方法を生徒に教え、使用している言語でコーディングスタイルをエミュレートします。

  1. いつかJavaにコードを変換するように求められる場合があります

本当だ!しかし、なぜJavaにとどまるのでしょうか?ある日、コードをベーシック、アセンブラー、またはperlに変換するように求められる場合があります。すべての言語にperlインタプリタが存在するため、プログラムを長いperl文字列として記述し、選択した言語で引数をマーシャリングします。

言語を変更する必要がある場合は、perl文字列をラップするコードを書き換えるだけです。

  1. 通常、C ++固有の機能を持たないコードの方が保守しやすい

使用する機能が少ないコードの方が保守しやすいことは事実です。また、すべての言語はチューリングマシンと同等であり、チューリングマシンはプログラミング言語の中で最も機能が少ないため、上記のperlインタープリターが実際にチューリングマシン(テープおよびすべて)を実行して問題を解決します。

  1. すべてのC ++言語固有の機能(例:多重継承)には、Javaで実装する代替手段が必要です。そうでない場合、設計パターンまたはコードアーキテクチャに問題があることを意味します。

C ++言語固有の機能には実際に価値のある用途があります。彼らはJavaではないので、それらは嫌悪感であり、それを使用する人々は異端者と決め付けることができます。C ++にこれらの言語機能がない場合、犠牲にする必要のあるものを見つけることができません。C ++言語機能が問題を解決します!


見て、C ++とJavaには異なる機能があります。C ++とJavaの交差点でのプログラミングは、両方の言語の利点のほとんどを捨ててしまったコードになります。

Javaは、C ++機能の悪用に対する反応として部分的に開発されました。これは、特に機能が成熟した数年後に反応が正当化されたことを意味するものではありません。

演算子のオーバーロードで恐ろしいことができます。しかし、すべてのコードがその言語で書かれることを止めない限り、その言語で恐ろしいコードが書かれることを防ぐことのできる言語はありません。

また、演算子のオーバーロードを使用して非常にエレガントな処理を行うこともできます。複素数または行列のように機能する複素数または行列クラスのような単純なもの。

Javaで利用できないC ++機能の使用に関する注意は、注意して表示する必要があります。現在のスキルレベルの開発者の現在のセットが機能を理解していないからといって、その機能を使用してはならないというわけではありません。同時に、機能を使用できるからといって、そうすべきだというわけではありません。ただし、Javaが多いショップでは、Javaに似ていない機能に対する抵抗力よりも抵抗力が強くなる可能性が高くなります。

言語間のコードの変換は、構造がどれほど類似していても、書き直しを行うのが最適です。そのような書き換えなしでそうしようとすると、惨めに失敗します。

多くのC ++固有の機能は、メンテナンスには不思議です。型の消去(などstd::function)を使用すると、階層を分離でき、依存関係が減少します。スマートポインターと確定的ライフタイムおよびRAIIは、実行時の驚きを減らし、リソースの定型を邪魔にならないようにします。重い静的型チェックは、コードが機能しないのではなく、コンパイルに失敗することを意味します。ミックスインはコードの重複を減らします。ADLを使用すると、型階層間のインターフェイスをアドホックに独立して拡張できます。Lambdaでは、使用場所の横にコードを記述できます。転送と移動はコピーを減らし、機能的なスタイル(副作用のない)プログラミングを効率的にします。演算子のオーバーロードは、ラインノイズを減らし、コードをモデル化する数学のように見せます。

チューリングタールピットに注意してください。すべての言語(テープ付きの生のチューリングマシンを含む)ですべてを実装できますが、そうする必要があるという意味ではありません。C ++でJava風の構造を使用してC ++機能をエミュレートするのは恐ろしい考えです。誰も読んだり理解したりできない保守不能なコードになります。

Javaデザインからインスピレーションて、C ++に移植できます。私は構文が好きなので、Python言語機能をC ++で実装することの大ファンです。しかし、それは、明示的な自己を取得する静的メソッドとしてクラスメソッドを作成し、非静的メソッド呼び出しを転送するラッパーを作成するという意味ではありません。

現代のC ++は、Javaがエミュレートして拒否する言語とそれほど似ていません。ある言語の機能に縛られないでください。「真の言語」はありません。新しい言語とその機能について学び、その特徴を吸収します。


1
-1、長々と不明瞭。
-djechlin

4
-1議論的、ストローマン的議論
user949300

28
+1、質問の適切な解体と私は笑った:)

11
+1。陽気なが、ポイントを保持します。実際にそれを読んでいる人々にとって非常に明確です。
ルイスMasuelli

14
「C ++とJavaの交差点でプログラミングを行うと、両方の言語の利点のほとんどが失われたコードになります。」頭に釘を打ちます!+1
Ajedi32

56

私はあなたの理由に答えるだけです:

  1. どうやってその結論に至ったのか分かりません。異なる言語には異なる機能があります。範囲、言語のアーキテクチャ、作成者の好み、さらに多くの理由に依存します。言語のいくつかの機能は悪いかもしれませんが、あなたの一般化は明らかに間違っています。
  2. JavaのようにC ++を記述すると、コードが悪化する可能性があります。たとえば、現在C ++ 11では、new / deleteの使用は避けていますが、共有ポインターを使用しています。あなたのシナリオでは、新規/削除のみに依存します。プログラマーがJavaのみを理解している場合は、Javaをトレーニングするか、より優れたJavaを雇います。
  3. それは起こりそうですか?そもそもJavaで書いてみませんか?新しい言語でプログラムをゼロから書き直すことは一般的に悪い考えであり、そのようなリスクには本当に良い正当化が必要と思います。
  4. これは単なる仮定です。
  5. 私見はシナリオやユースケースに大きく依存しています。

27
また、Javaプログラマはdeleteどちらも使用しません。
パエロエベルマン

8
Javaプログラマーが知らないことによって引き起こされるメモリリークを修正する必要がありましたdelete。私が思い出すと、これらのケースの少なくとも1つでは、動的割り当て(new)も必要ありませんでした。
イーサンカミンスキー

16
@EthanKaminskiええ、それはあなたがC ++初心者、特にJavaのバックグラウンドなどから来た人を簡単に見つける方法です。すべてにnewを使用するのをやめてください。
ルアーン

1
@PaŭloEbermannはい、さらに悪いことです。
サイモン

1
「あなたのシナリオでは、new / deleteのみに依存します」-おかしい、私は「Java(like)-features only」のC ++イディオムが排他的に使用されると思っていたでしょうmake_shared
カイルストランド

26

Javaには、組み込みの高速で信頼性の高いガベージコレクター、単一ルートオブジェクト階層、強力なイントロスペクションなど、C ++にはない機能があります。

Javaのその他の機能は、Java専用の機能と連携するように設計されています。JavaのC ++機能の省略の多くは、新しい機能が不足を補うために可能です。たとえば、Javaには確定的なデストラクタを持つスタック割り当てオブジェクトはありませんが、最終的にブロック(およびJava 7以降のtry-with-resources)と、この不足を補うガベージコレクタがあります。

C ++には、最終的にブロックやガベージコレクションがありません。デストラクタがJavaに存在しないために使用しない場合(ファイナライザはカウントしません)、Cレベルのリソース管理(つまり、すべてのマニュアル)を使用しますが、クリーンアップをグループ化することさえできません。 Javaにもgotoがないため、移動先のクリーンアップブロックに移動します。保守性が向上すると本当に思いますか?

Javaには、すべてのクラスが最終的にObjectから派生する包括的なオブジェクト階層があり、いくつかのプリミティブ型もそのようなクラスに自動ボックス化できます。これにより、オブジェクトへのポインターを保持するために、オブジェクトのコンテナーを1回書き込むことができます。Java 5はジェネリックを導入しました。ジェネリックは、そのようなコンテナが必要とするキャストを取り除きますが、ほとんど同じコードにコンパイルします。

C ++にはそのような階層はありません。複数のタイプで機能するコンテナーの作成を容易にするために、テンプレートを使用します。テンプレートは、さまざまなタイプの必要に応じてコンパイラーによってインスタンス化されるブループリントです。テンプレート(およびマクロ)の使用を禁止し、異なるタイプに対して同じコンテナコードを何度も記述するか、またはvoidポインターを使用するCルートに進みますか?(待ってください、Javaにはvoidポインターはありません!)これにより保守性が向上することを確信していますか?

まともな言語には、連携して動作するように設計された多数の機能があります。言語Bには機能がないため、言語Aの機能を禁止することにより、言語Aが機能しなくなります。これは、Bを一貫性のあるものにする機能をBから同時に追加しないためです。

それは、C ++の許可された機能を制限してはならないということではありません。C ++は歴史的に大きく成長した言語であり、プログラマーが安全性と使いやすさよりも望んでいることを行えるようにすることを強調しています。一部の機能の使用を制限する多くのコーディング標準があります。たとえば、Googleのガイドラインでは、多重継承、複雑なテンプレート、例外をほとんど禁止しています(ただし、最後のものは歴史的な理由によるものです)。ただし、「Javaにはないため」という機能は禁止されていません。機能はC ++のフレームワーク内でのみ考慮されます。


27
熟練したC ++のベテランは通常、Googleコーディングガイドラインを拒否します。最新のC ++は、これらの機能を使用しているため、非常に優れいます。はい、それはさらに異なっています。
-Jan Hudec

17
C ++にはfinallyブロックがありませんが、RAIIがあるため、ほとんどの場合、はるかに優れていることに注意してください。そして、再び、異なる。
-Jan Hudec

7
Java Objectvoid*ほとんどの用途に適しています-それでも、うん。
クエンティン

1
機能の選択を超えて、スタイルとイディオムの問題があります。通常、プログラムは、作成された言語の通常のイディオムを使用すると、読みやすく、保守しやすくなります。Javaに似た機能のみを使用してC ++プログラムの一部を記述できたとしても、結果は奇妙で高尚なC ++になります。
パトリシアシャナハン

2
私は正しい答えを出すためにこの答えを支持します(「やらない」)が、JavaはC ++よりも「高度」であるという基本的な前提に我慢できません。C ++はありません必要私はので誤る...申し訳ありませんが、私は、文を終了する方法がわからない...ガベージコレクタまたはシングルルートオブジェクト階層、Javaが必要としないのと同じ方法を欠場 Javaで確定的なデストラクタをし、finallyそれらに代わるものではありません。2つの言語は根本的に異なります。
DevSolar

25

完全に合理的な結論と思われる数値に既に達している場合、別の答えを投稿するかどうかを議論しました。あなたのアイデアは、基本的に災害を待っています。しかし、彼らはその結論の背後にある関連性の高いいくつかの理由を指摘できなかったと思います。

JavaとC ++の違いは、焦点を当てていると思われる詳細よりもはるかに深く実行されます。

たとえば、C ++での多重継承の禁止について話します。最初に、これは単にポイントが欠落していることを指摘します。Javaは、「インターフェース」を「クラス」とは別のものとして定義します。1つのクラスは他の1つのクラスからのみ継承しますが、任意の数のインターフェイスを実装できます。

C ++は、2つの概念をそのように分離しません。Java でのインターフェースの実装に最も近いアナログC ++は、別のクラスから継承しています。そのため、2つを合理的に整列させるには、おそらくC ++で多重継承を使用する必要がありますが、Javaがクラスと比較してインターフェースを制限するのとほぼ同じ方法で基本クラスの一部を制限する必要があります(つまり、本質的に関数のシグネチャを指定しますが、少なくともほとんどの場合、実装は指定しません)。

しかし、それは2つの間の実際の違いの表面をかろうじて引っ掻いているだけです。Javaコードは、インタフェース、およびそれらのインターフェイスを実装するクラスを定義する可能性がある場合、実際には、C ++コードが動作しますいくつかのテンプレートを定義する可能性が高いがたくさんある任意の(ちょうどそれらは、インターフェイスを実装するために、具体的にその要件を満たしているクラスが定義されていません(s)指定します)。

基本的に「C ++構文を使用するJava」であるコードが正直に必要な場合は、ほぼ間違いなく、後者に似たものをすべて禁止する必要があります。テンプレートの使用を、Javaジェネリックがサポートする「Tのコンテナー」のレベルに制限する必要があります。残念ながら、それを行うと、他のプログラミング言語に翻訳する長期的な可能性は言うまでもなく、C ++コードは非常に混乱し、現在の状態を維持できなくなります。

将来、他の言語に変換できるコードが本当に必要な場合は、できるだけきれいで読みやすいコードになるように努めてください。理想は、擬似コードを記述し、それを実行させることです。よく書かれた最新のC ++アプローチは、あなたが提案したサブセットよりもはるかに厳密に理想に近づいています。どのように記述しても、Javaに翻訳する場合は、個々のステートメントの構文だけでなく、実際にコードを翻訳する必要があります。


多くのC ++機能は、Javaの概念にうまく対応するいくつかの方法とそうでない方法で使用できます。プログラムの一部は、言語の機能の重複するサブセットの外に何かを必要とし、「C ++構文を使用したJava」のような部分を書き込もうとすると、恐ろしい混乱が生じます。一方、コードの他の多くの部分は共有サブセットの外にあるものを必要とする可能性があり、コードの外に出ることを説得する理由がない部分については共有内にとどまるのが役立つかもしれません。
-supercat

おそらく「必要かもしれない」と言う場合、あなたは本当に「必要ではないかもしれない」という意味ですか?そうだとすれば、私は同意する傾向があります。
ジェリーコフィン

うん。C ++ではなくJavaをサポートするプラットフォームをサポートする必要が生じた場合、コードの一部をほぼ確実にゼロから書き直す必要があり、それらの部分がJavaに優しい技術を使用して記述されているかどうかは関係ありません。とにかく書き換えられます。ただし、他の部分を完全に書き直さずに移行できる方法で記述することは可能かもしれません。また、場合によっては、そうするために必要な追加費用が最小になる可能性があります。
-supercat

4
@supercat:OTOH、JavaをサポートしているがC ++をサポートしていないプラットフォームの数を考えると、これはほとんど完全に問題を探すための解決策だと思います。
ジェリーコフィン

しばらくの間、ブラウザのJavaアプレットのサポートは、C ++アプレットよりも優れていました。ただし、JavsScriptのブラウザーサポート(Javaとは関係ありません)は、基本的に両方から引き継がれるほど十分に改善されています。
-supercat

11

言語Xでコードを作成する場合は、時間をかけて言語を適切に学習し、提供されるすべての機能を使用して問題の解決に役立ててください。日本語から英語、JavaからC ++のいずれであっても、ある言語から別の言語へ「単語から単語へ」翻訳しようとすると、悪いことが起こります。問題の十分な理解から始めて、使用されている言語にとって最も自然な方法でソリューションを表現する方がはるかに優れています。

コードの作者はたまたまCを使用しているFortranプログラマーだったため、インデントがなく、すべてのステートメントが列7で始まるCプログラムを見ました。ポインターをポインターに言及する心がなかったので、その場で気を失っていただろうと思います。

このコードを将来維持するために誰かを雇うことを想像してください。優れたC ++コードであれば、有能なC ++開発者を雇うことができ、彼らは自分の道を見つけることができるはずです。「Java in C ++」の場合、C ++開発者もJava開発者もコードを簡単に理解することはできません。


7

あなたの理由はすべて反証することができます:

JavaがC ++の機能を提供しない場合は、その機能が適切ではないことを意味するため、使用しないようにする必要があります。

機能が良くないという意味ではありません(本質的に悪い機能はありません)。これは、機能が頻繁に悪用されたことを意味します(または、ダイレクトポインターとガベージコレクションのような基本的な概念のために実装が不可能です)。定義上、Javaはより簡単でプログラマーに優しいことを目的としているため、簡単に悪用できることが証明された機能が削除されています。

C ++固有の機能(例:フレンド関数、多重継承)を備えたC ++コードは、C ++プログラマーのみが保守またはレビューできますが、JavaのようなC ++(C ++言語固有の機能なし)を記述するだけで、コードは両方によって保守またはレビューできますC ++およびJavaプログラマ。

あれ?最も単純なC ++コードを見てみましょう。

int len = mystring->size();

おっと、「言語固有の」機能は使用されていませんが、Java開発者はすでにメンテナンスできません。Javaでは「。」で逆参照するため ここでは「->」です。

いつかJavaにコードを変換するように求められる場合があります

またはC#。またはハスケル。またはPython。またはルビー。またはCOBOL(はい、できます!)。どうやって未来を伝えることができますか?

C ++固有の機能を持たないコードは、通常、メンテナンス性が向上しています。

正反対。すべての機能は、プログラミングを容易にし、メンテナンス性を高めるために導入されました。例:フロートで動作するプログラムを取得します。それをアップグレードして、複素数を処理します。オペレーターの救助に過負荷!

すべてのC ++言語固有の機能(例:多重継承)には、Javaで実装する代替手段が必要です。そうでない場合、設計パターンまたはコードアーキテクチャに問題があることを意味します。

しかし、Javaには多重継承があります!「インターフェース」と呼ばれます。Javaの実装は、すべてがから派生することによる恐ろしいダイヤモンドを回避するための問題のある回避策Objectです。それinterfaceは、どの唯一の目的がから派生しない何かになることを紹介することによって行われObjectます。C ++にはこの問題はありませんでした-必須の共通ベースがないため、すべてのクラスがひし形のないインターフェイスとして機能できます。

サイドノート:Javaが最近導入した...インターフェイスの具体的なメソッド。C ++は常に存在しなかった問題を常に解決しなければならない機能を追加しました。

また、ごく少数の「C ++にはあるがJavaにはないもの」についても言及しました。C ++とJavaの最大の違いの1つは、メモリレイアウトの制御です。(Javaのように)オブジェクトへのポインターの配列を作成するか、連続したメモリブロックを作成できます。さて、Java開発者を誤解させる可能性のあるC ++機能について心配する場合、これは私のリストで、複数の継承やオーバーロードされた演算子のような一見して明らかで認識可能なものよりもはるかに高い隠された微妙なものです。

結論:クリーンコードはクリーンコードです。JavaまたはC ++-同じ違い。シンプルにしてください。不必要な合併症は、不正なコードの主な原因です。


Javaは、C ++のすべての機能を提供する言語ではサポートできない機能と保証を提供します。たとえば、言語では、C ++に含まれる一般的な形式の多重継承を提供しながら、動的な型の読み込みとJavaのID保持キャストのすべてを許可することはできません。
-supercat

@supercatここでこれを言っている理由がわかりません。問題は、C ++で再現できないJava機能に関するものではなく、Javaが破棄したC ++機能に関するものです。
Agent_L

私のポイントは、Javaの一部の機能はC ++に含まれていませんが、Javaの一部の機能はC ++に含まれる他の機能と基本的に互換性がないため、両方をサポートする型(C ++ / CLIなどの言語C ++機能をサポートするタイプとJava風の機能をサポートするタイプがありますが、相互運用性が制限された別々のユニバースに効果的に生息しています)。
スーパーキャット

6

いいえ、通常はJavaのようにC ++を書くべきではありません。また、Javaには存在しないC ++言語機能を絶対に省略するべきではありません。

一つには、Javaはガベージコレクションされるため、C ++の「delete」キーワードに相当するものはありません。さて、ルールに従って許可されていないため、削除せずにプログラムを実装します。

おめでとうございます、あなたは今メモリリークを持っています;)。それも理論的ではありません-この正確な状況はオープンソースゲームで起こるのを見ました。

同様に、JavaにはC ++ポインターのようなものはありません。C++ポインターは、多くの一般的な関数呼び出し規則を排除します。

避けるべきC ++の機能があります(以下を参照)が、「Javaに含まれていない」ことはリトマステストとしては適切ではありません。


より良いガイドラインは次のとおりです。

  1. 言語、環境、およびツールに適したコードを作成します。
  2. チームが理解できるコードを作成します
  3. チームが指定されたドメインで有能であることを確認してください。

項目(3)は、C ++でトレーニングしない限り、C ++でJavaプログラマーのコードを持ってはならないことを意味します。微妙ではあるが非常に重要な違いがありますが、Javaの奇妙な方言のように扱いようとする場合、彼らはそれを学ぶことはできません。

項目(2)は、チームが多重継承に特に不快な場合(たとえば)、それを使用しない適切なソリューションがある場合、その代替ソリューションを使用するのが最善であることを意味します。ただし、これは特にチームに依存します。一方、チームが多重継承よりもその代替ソリューションの方が不快な場合は、多重継承を使用してください!


最後に、C ++の言語機能がありますが、おそらくこれは避けるべきです。これらが何であるかを知りたい場合は、異なる言語のプログラマーではなく、C ++プログラマー尋ねてください。開始するいくつかの例は、ポインター演算(普遍的なコンセンサスなし)とgotoです。


6

他の回答にはすでにいくつかの良い点がありますが、より完全な回答を提供し、質問や声明を個別に取り上げたいと思います。


JavaがC ++の機能を提供しない場合は、その機能が適切ではないことを意味するため、使用しないようにする必要があります。

これはかなりよく回答されています。JavaはC ++の「良い部分」ではなく、そう考える理由もありません。

特に、個々のC ++機能のメリットは議論の余地がありますが、Javaの設計者が悪い考えだと思ったため、Javaの一部ではないC ++ 11 / C ++ 14の機能の多くは必ずしも除外されません。例として、バージョン8まで、Javaにはラムダはありませんでしたが、C ++ 11標準でC ++に導入されました。Java 8より前は、Javaに欠けているC ++機能が「良くない」ために設計上欠けていたという仮定は、言語機能としてのラムダは「良くない」ことを暗示していました(どこにいるLISPerの恐怖にとってもおそらくあなたが実際 Java が好きだと聞くほど恐ろしいでしょう)。しかし今、JavaデザイナーはラムダにStamp of Approval(TM)を付けているので、今では良いことです。

さらに深く掘り下げると、Java 8でさえ、lambda-as-closureはC ++ 14のラムダほど柔軟ではありませんが、これは、より柔軟なアプローチが悪いという意識的な決定ではなく、JVMアーキテクチャの制限による可能性があります言語設計の観点。


C ++固有の機能(例:フレンド関数、多重継承)を備えたC ++コードは、C ++プログラマーのみが保守またはレビューできますが、JavaのようなC ++(C ++言語固有の機能なし)を記述するだけで、コードは両方によって保守またはレビューできますC ++およびJavaプログラマ。

これが私が対応したかった主なものです。

大まかに言って、使用している言語に精通していないプログラマーからコードレビューを取得することには、いくつかの価値があるかもしれません。関数/メソッドの名前とコメントの明快さに関する貴重なフィードバックを提供できます。また、(質問が正しく示すように)言語が既に知っている1つ以上の言語に類似している場合、基本的なプログラムフローに従うことができます。潜在的に論理エラーをキャッチします。

しかし、それはありませんレビューのこの種は今まで実際に使用している言語を知っている開発者からのレビューや「と同等の」「と同じくらい良い」となることをケース。本質的に、これは、ある言語別の言語のように見せると通常微妙な違いが隠され、一方、ある言語を別の言語のように振る舞う(特にC ++とJavaの場合)ことは言語にとって非公平であり、かつ/または依然として混乱を招く可能性があるためですレビュアー向け。

まず、C ++をJavaの「見た目」にすることの意味について考えてみましょう。単純なケースとして、newJavaの場合と同様に、オブジェクトのインスタンス化に使用できます。

Foo foo = new Foo();

しかし、この方法でインスタンス化されたオブジェクト->.、メソッドを呼び出す代わりに使用するため、メソッド呼び出しをJavaのように見せたい場合は、代わりに次のように記述する必要があります。

Foo& foo = *new Foo();

しかし、これは馬鹿げたことではありません。特に、を使用してメモリを後でクリーンアップする必要があります一部の経験豊富なC ++delete &foo開発者は、合法的なコードであることに気付かない場合があります。どちらにしても、全体に振りかけ面白い非Javaのような記号があるので、我々はできませんかなりの言語は、Java「のように見える」します。(*newを使用して削除することもできますが#define New *new、さらに悪いことに、を使用すると、#define new *new仲間の開発者があなたを嫌うように懇願します。)そして、上記のようdeleteにJavaには存在しないため、いずれにしても(別の回答)メモリリークなしでJavaのようにオブジェクト使用法を実際に「見える」ようにすることはできません。

しかし、最新のC ++にはスマートな共有ポインタが含まれており、Javaのメモリ管理変数参照によく似ています。だからあなたが書くことができるJavaのどこでも、Foo foo = new Foo();代わりに書くことができます:

std::shared_ptr<Foo> foo = std::make_shared<Foo>();

今では、実際にJavaの内部によく似た言語機能を使用しています。しかし、突然、C ++以外のレビュー担当者に説明することがたくさんありshared_ptrます。これは何ですか?微妙なトリッキーな「落とし穴」はmake_shared何ですか?(これは、いくつかの失敗例があり、呼び出されている「間違った」コンストラクタにつながることができ、完全な転送を、使用しています。)なぜ方法がで呼び出す必要があります->が、使用して.いくつかの方法では、コンパイラによって許可されていますか?(shared_ptrメソッドが場合。独自のメソッドを持っている)Foo::reset(void)が存在し、不注意な開発者はでそれを呼び出すようにしてみてくださいfoo.reset()(一つだけの共有ポインタが存在する場合のそのインスタンスを指している、Foo基礎となるメモリを削除し、無効になりますコールが発生した場合)foo、およびJava開発者はこの問題をキャッチする可能性は低いです。

また、C ++が持っているたくさん落とし穴ある特定言語を。私の知る限り、ほとんどのC ++開発者は、「安全な」C ++プラクティスの独自のイディオムを徐々に開発することにより、これらの落とし穴に対処することを学びます。 Googleコーディングプラクティスと、「Seasoned C ++のベテランは通常Googleコーディングガイドラインを拒否します」というコメント。言語は複雑すぎるかもしれないとの主張はすべて(少なくとも私の経験では)、「まあ、間違って使うのはやめなさい」というバリエーションに出会うようです。これはC ++コミュニティに対する非常に否定的な見方であり、言語学習者を支援したいと思っている経験豊富な開発者もいますが、 例えば、未定義の振る舞いに対するある種の防御力のようです(たとえば、上記の「落とし穴」リンクの議論の多くを参照してください)。

Java開発者は、コードレビューを介してこれらの落とし穴を見つけて修正するのに役立ちません。


いつかコードをJavaに変換するように求められる場合があります。

設計段階にあるときに将来コードに何が起こるかを考慮しようとすることは、完全に妥当です。

しかし、最初に、この特定の考慮事項は、リモートの可能性のように思われます:コードは通常、そのまま再利用されます(たとえば、JNIインターフェースを使用して、作業C ++コードの一部またはすべてを将来のJavaソフトウェアにプラグインできます)直接手動で「転写」するより。

そして、第二に、あなたは後で言う、

すべてのC ++言語固有の機能(例:多重継承)には、Javaで実装する代替手段が必要です。

これは基本的に、「Javaに変換」ポイントをキャンセルします。ソフトウェアが慣用的なC ++で記述され、その後慣用的なJavaに変換される場合、この変換がC ++機能のJava機能への正確な1対1マッピングを適用することにより行われることを期待する理由はありません。


C ++固有の機能を持たないコードは、通常、メンテナンス性が向上しています。

ここで何を意味するのかは明確ではありませんが、実際にはこれにある程度同意します。細心の注意を払っていない限り、C ++機能は保守性の問題につながる可能性があります。C ++ FQA Liteは(少なくとも実際にはかなりよくそれを理解するように見える誰かから言語とその支持者の重要なウェブサイト)があることを述べて

...開発者の80%が言語の最大20%を理解しています。異なる人々にとって同じ20%ではないので、互いのコードを理解することを期待しないでください。

注意してください:あなたがC ++ファンであり、私の答えでこの点に達し、FQAの作者が実際にC ++を理解していないか、彼の議論のほとんどで不誠実であると主張するコメントに飛び降りたいと思う場合、(1)彼を引用した後の正確に2つの文、FQAは非常に偏りのあるソースであると認めます。(2)FQA作成者がC ++を理解しているかどうかは、私が何を言おうとしても重要ではありません。 、C ++をbashしようとしていないので、FQAを引用したからといって、私が反C ++であると想定せずに、残りの記事を読む必要があります。メモの終わり。

同様に、Linus Torvalds は本質的にこの理由でC ++を嫌っています(警告:リンクは、真の悪名高いLinusスタイルで、多くの宣誓を伴います)。

明らかに、これらは非常に偏った問題ですが、C ++の支持者でさえ、言語機能セットのすべてを使用すべきではないと言うことがよくあります(もう一度、Googleコーディングガイドラインを参照してください;また、C ++の作成者であるBjarne Stroustrup 、「C ++の中には、抜け出すのに苦労しているずっと小さくてきれいな言語があります」と公に述べています。

そのため、特にJavaのバックグラウンドから来ている場合は、C ++の機能は簡単に誤用される可能性があるという考えにはいくつかのメリットがあると思います。さらに、言語の一部に自分自身を制限することにより、これらの問題を軽減するというアイデアにはメリットがあります。

しかし、決定され、別の言語に基づいて使用するサブセットはないではない「異なる言語が」Cでない限り、本当にC ++言語のCのようなサブセットがあるので、正しいアプローチのように見えます。(Linusは上記の彼の暴言でこれを参照し、Scott Meyersはこのサブセットを「サブ言語」と呼ぶこともあります。)Javaのランタイムパラダイム(ガベージコレクション、VM上で実行)は、C ++とは根本的に異なります。 C ++の使用法について学ぶべき有益な教訓があることは明らかではありません。上記のように、Javaから直接C ++についての教訓を引き出しようとすると、非常に非自明なコードにつながる可能性があります。

代わりに、言語の慣用的な使用方法を理解した上で、言語の「受け入れ可能なサブセット」を定義してください。Cが提供する以上のC ++の機能の多くを引き続き活用するかなり制限的なサブセットが必要な場合は、前述のGoogle Codingガイドラインを開始するのに適している場合があります。確かに、いくつかのGoogleの制限には「合理的な議論はない」と言う開発者がいますが、アレクサンドレスクをD言語での仕事(それ自体が何かを伝えるはずです)から雇いたいと思わない限り、それはおそらく大丈夫。C ++をJavaに変換するよりも確かに優れています。

コードガイドラインセットのもう1つの良い出発点は、Bjarne StroustrupとHerb Sutterによる進行中の作業である新しいC ++ Core Guidelinesです。

C ++の欠点に対処する唯一の他の方法は、別の言語を選択することです。あなたはJavaが好きで、このプロジェクトが最終的にJavaに変換される可能性があると思われます。別の答えで述べたように、あなたはただ... Javaから始めることができます。

Java以外の何かを本当に使用する必要がある理由は2つあります。

  1. 実行時のパフォーマンスが本当に必要です。この場合、C ++をJavaのように扱うことは実際には役に立たないでしょう。共有ポインターなどのJavaのような手法は実行時のパフォーマンスを低下させるからです。
  2. JVMをまだサポートしていないあいまいなプラットフォームで動作するソフトウェアが必要です。この場合、おそらくGCCまたはClangフロントエンドを備えた言語にこだわっています。CとC ++は明らかな候補ですが、Rustのようなものを調べることもできます。(クイックプラグ:Rustを広範囲に使用したことはありませんが、見た目が素晴らしく、できるだけ早くRustの主要なプロジェクトに取り組むことを切望しており、C ++プロジェクトを開始することを検討しているすべての人がRustを代替として検討する必要があります)

すべてのC ++言語固有の機能(例:多重継承)には、Javaで実装する代替手段が必要です。そうでない場合、設計パターンまたはコードアーキテクチャに問題があることを意味します。

これについてはすでにある程度取り上げましたが、意図的に2番目の文を省略しました。

constexprJavaのような部分的にJITの言語では意味をなさないのようなものが、無効なアーキテクチャを示していることを確信していません。テンプレートメタプログラミングの過剰な使用は価値があるよりも多くの問題があるかもしれないという考えをよりオープンにします。特に、constexprコンパイル時の関数評価を行うために存在しますconstexprが、デザインの欠陥がない場合は明らかです'それを使用しています:コードを実行する前にいくつかの計算が行われるようにするだけです。これは素晴らしいパフォーマンスの向上です(たとえば、別のエントリを除く他のすべてのエントリよりも優れているThe Benchmark Gameのn体問題のこのエントリを参照してください)C ++で書かれた、


5
FQAの著者は間違いなく「言語の最大20%を理解する」グループに分類されます。事実上間違っているかなりの数の答えと、ストローマンの後にストローマンで示されている、ポイントを逃しただけのたくさんの答えがあります。
ベンフォークト

2
C ++ FQAの苦情の多く(ほとんどすべて?)はナンセンスです。現代の言語は巨大です。C ++は、Python、Ruby、Perl、そしてJavaに比べてかなり小さいです。stackoverflowの上で、これらの言語での基本的な質問をすると、最初の答えは、の線に沿って、ほぼ必然的にある「なぜあなたはなかったimport SomeVeryBasicPackageとだけやる、これを?」高度な質問をすると、最初の答えは、の線に沿って、ほぼ必然的にある「なぜあなたはしませんでしたimport SomeMagicalPackageし、ちょうど行うことを?」
デビッドハンメン

1
@DavidHammen 80/20分割は、標準ライブラリコンポーネントだけでなく、コア言語機能を指すと思います。この場合、Perlを除き、言及する言語はC ++ほど大きく複雑ではないようです。いずれにせよ、それは私の答えの非常に小さな部分であり、私はそれが偏った情報源であることを認めました。
カイルストランド

1
VM /マネージ言語は明らかに表面的にははるかに複雑ですが、使用の観点からは複雑です。
カイルストランド

1
あなたの理論が正しいかどうかはわかりませんが、私の場合、私は間違いなくC ++とCを別々に学び、私のC ++クラスは本当に徹底的でした。しかし、20/80の分割についての完全な引用は、すべてのプログラマーが言語の異なる 20%を知っているということです。これは、ほとんどのプログラマーが言語のC部分を個別に教えられても説明できません。とにかく、C ++がより堅牢なプログラミングを可能にする方法を詳細に説明したい場合(前に見たことがありますが、理解していません)、ここのコメントではなくチャットルームか何かで行うのが最善です。
カイルストランド

5

プロジェクトの環境によってC ++の使用に制限されているとします。C ++にはあるがJavaにはない言語機能(たとえば、多重継承、演算子のオーバーライド)の使用を防ぐのは良いことですか?

番号。

「プロジェクトの環境によって」C ++の使用に制限されている場合、それを個人的にどのように使用/福音化することを好み/望んでも、他の技術について考えることさえほとんどありません。
「テクノロジーX」または「Y」は、任意の特定の機能をサポートしているかどうかは持つべきではないものは何でも何の関係、あなたのC ++アプリケーションを構築する方法についてを。
これはおそらく「良い理由」(現在または過去)のためのC ++アプリケーションなので、特定の「ツールボックス」が提供するものを使用し、C ++アプリケーションとして作成する必要があります。

アプリケーションを他のテクノロジーに移植する要件がある場合、その場合(そしてその場合のみ)、他のプラットフォームの機能を検討する必要があります。何か起こるかもしれないという偶然には「鼻を切って顔をいじる」という意味はありません。ただし、大規模な書き直しは高価でリスクの高い操作であり、管理者が非常に正当な理由なしに実行する可能性は低いことを忘れないでください。

Visual Basic [.Net]の世界で数年前に似たような(「使用するかしないか」)の議論がありました。 Microsoft.VisualBasic名前空間によって提供される機能。std ::名前空間なしでC ++アプリケーションを記述しようとするようなものです。OK、それは可能ですが、なぜ地球上で彼らの正しい心の誰かがそうするのを煩わせるのでしょうか?


1
Visual Basicに関する最後のポイント:このようなベンダーライブラリの問題は、それらが独自仕様であるということです。それらを使用することは、そのベンダーに自分自身を連鎖させることを意味します。ベンダーはあなたが連鎖されることを好むでしょうが、長期的にはそうではありません。ベンダー固有の機能に依存するすべてを書き直さずに他のベンダーのソフトウェアを使用することはできません。ベンダー固有の機能を使用すればするほど、ベンダーを変更するコストが高くなり、ベンダーが変更を強制できるようになります。それが、フリー(自由のように!)ソフトウェアが非常に重要な理由の1つです。
cmaster

Microsoft.VisualBasic名前空間の事はストレッチのビットです。私が最後に使ってから何年も経ちましたが、少なくとも最初は主にVB6との後方互換性を目的としていました(および/またはVB6プログラマーに「アットホーム」な気分にすること)。ほとんどの場合、フレームワークの他の部分ですでに利用可能な機能をよりモダンな(より統合された)形式で提供していたため、新しいプロジェクトでは使用する意味がほとんどありませんでした。反対に、std::名前空間は標準ライブラリ全体が存在する場所です。それを回避することは、.NETでBCL全体を回避することに似ています。
マッテオイタリア

2

現在の答えはすべて、これは悪いことだと言っています。使用している言語を利用し、C ++機能がjaveにないからといって「悪くない」理由を説明する必要があるからです。 別の角度からこれに答えます。

多重継承、演算子のオーバーロード、独自のテンプレートの定義などの複雑なC ++機能を避けることは1つのことです。

しかし、最も単純なタスク以上のことを行う問題:

  • メモリを割り当て、
  • そのお金をポイントと結び付ける
  • データ構造を構築する
  • その後、安全に使用できるときにメモリを再利用できます

上記を可能にするJavaとC ++の共通のサブセットはないため、求めていることは不可能です。(JavaとC#について質問している場合、どちらもガベージコレクターを使用しているため、はるかに良いチャンスがあります。)

ただし、Java開発者が何を行うか(詳細な「方法」ではなく)を理解できるようにコードを記述する必要があり、これは賢明なことです。

C ++とJAVAの両方で実装した独自の言語を設計することもできます。


0

他のコーダーが理解できないコードを誰も書いてはいけません。言語ロックが問題だと思われる場合は、開発者がロックするまで待ちます。1つは他の人よりも人質になりやすいです。

技術的な理由はありません。あなたが作成したのは、何らかの理由で言語が使用されたシナリオですが、現在および将来の多くの開発者はそれを実際に理解していません。

私の推測では、Java開発者はJavaで記述する方法でC ++を作成する可能性が高いので、なぜそれをルールにするのでしょう。Java開発者向けの小さなC ++命令/ドキュメントを使用すれば、Java混乱の大群よりも簡単に実装および保守できるC ++固有の機能を見つけることができます。

これは、オブジェクト指向言語に移行するBASICプログラマーの問題に関する議論です。理解していない新しい開発者に損害を与えてOOPプラクティスを実装しているのではなく、まったく実装していないということです。もしそうなら、彼らは通常それを間違えます。何かがうまくいかない場合は、理由に関係なく削除する必要があります。

盲目的にコードをコピーして貼り付けるだけでなく、彼らは理解できない多くの領域でそれを実行します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.