2012-01-31 24 views
60

私はC++を学ぼうとしているJava開発者ですが、標準関数宣言のベストプラクティスが本当にわかりません。クラスの内部または外部の関数宣言

クラスで

class Clazz 
{ 
public: 
    void Fun1() 
    { 
     //do something 
    } 
} 

や外部:私は二番目は読みにくくなることを感じている

class Clazz 
{ 
public: 
    void Fun1(); 
} 

Clazz::Fun1(){ 
    // Do something 
} 

...

+5

おそらく初心者のC++の本が注文されている可能性がありますか? –

+28

@Downvotersなぜですか?私の質問に何が間違っていますか? – JohnJohnGa

+0

ここには実際に3つのオプションがあります。 2番目の例では、ヘッダファイルに関数定義を含めることができます(ただし、まだインライン化されていません)。または、別の '.cpp'ファイルに定義されています。 –

答えて

13

最初は、あなたのメンバ関数を定義しますinline functionとして表示されますが、2番目の表示は表示されません。この場合の関数の定義はヘッダそのものに存在します。

2番目の実装では、関数の定義をcppファイルに置きます。

両方が意味的に異なり、それは単なるスタイルの問題ではありません。

+1

http://www.cplusplus.com/doc/tutorial/classes/にも同じ答えがあります: "クラスメンバー関数をクラス内で完全に定義することと、プロトタイプとその定義だけを含めることの唯一の違いは、最初のケースでは関数は自動的にコンパイラによってインラインメンバ関数と見なされ、2番目は通常の(インラインではない)クラスメンバ関数になりますが、実際には動作に違いはないと考えています。 – Buttons840

2

最初のものは、ヘッダーファイル(クラスの宣言があるところ)に置く必要があります。 2つ目は、ヘッダーか通常はソースファイルのいずれかになります。実際には、クラス宣言(暗黙的にインライン宣言していますが、最終的にインライン化するかどうかを決定するコンパイラですが)に小さな関数を入れることができます。しかし、ほとんどの関数は、ヘッダーに宣言があり、2番目の例のようにcppファイルに実装されています。そして、いいえ、私はこれがなぜ読みにくくなるのかはわかりません。言い換えれば、実際には、いくつかのcppファイルに渡って型の実装を分割することができます。

37

C++は、ソフトウェア開発のためのオブジェクト指向のパラダイムをサポートするという意味で、オブジェクト指向です。

しかし、違った、Javaから、C++はクラスでグループ関数の定義にあなたを強制するものではありません:関数を宣言するための標準的なC++の方法は、ただのクラスせずに、関数を宣言することです。

代わりに使用すると、メソッドの宣言/定義の話をしている場合は、標準的な方法は、インクルードファイル(通常は.hまたは.hppという名前)と(通常は.cppまたは.cxxという名前の)別の実装ファイルでの定義でちょうど宣言を置くことです。私はこれが実際にいくらか迷惑で、いくつかの重複が必要だと同意するが、それはどのように言語が設計されたかである。迅速な実験と単一のファイルについては

は、何かがうまくいく突き出...しかし、大きなプロジェクトのために、この分離は、実質的に必要とされるものです。

注:Javaを知っている場合であっても、C++が完全に異なる言語である...そして、それは実験によって学習することができない言語です。なぜなら、それは多くの非対称性と明らかに非論理的な選択肢を持つかなり複雑な言語であり、最も重要なのは、あなたが間違いを犯すとJavaのようにあなたを救うための "ランタイムエラーエンジェル"はないが、未定義の動作デーモン "を参照してください。

C++を学ぶ唯一の合理的な方法は、読んでいることです...どのように賢明であっても、委員会が何を決定したかは分かりません。正確な答えは非論理的であり、歴史的遺産の結果であるため、実際にはスマートになることも時々問題になります。good bookまたは2つを選んでカバーを読むように読んでください。

+4

誰かがJavaから来て、C++のヘルプを求めたら、「あなたが知っている言語が何かに執着している」と言ったら、それは何を教えてくれますか?彼は他の言語との比較をしていないので、ほとんど知られていません。あなたは強く感情的に抱かれたような言葉を使用するよりも、OPにはあまり言わないが、この部分を外に出すことを検討するかもしれない。さらに、「すべてのためにクラスを使用する」というコンテキストは何ですか? Javaでは、メソッドにクラスを使用しません。変数にはクラスを使用しません。あなたはファイルのためにクラスを使用しません。だから、ここの「すべて」は何ですか?ラント? –

+1

@DanielS:明らかにあなたに怒っているので、その部分を削除しました(理由は分かりません)。確かに、私は実際にはJavaを全く使わないのでJavaについて怒らないのですが、Object Obsessed ProgrammingとしてのOOPは面白い冗談だと思ったのですが、明らかにそうではありません。私はJava 1.1認定のプログラマーでしたが、何らかの理由で強制されない限り、私はその「プログラミング言語」を使用しないで、これまで避けていました。 – 6502

+0

ありがとう、私はそれが今よりずっと良いと思う。申し訳ありませんが、私は怒っていると思います。私は次回よりポジティブになるよう努力します。 –

12

クラス外では関数の定義が優れています。そうすれば、必要に応じてコードを安全に保つことができます。ヘッダーファイルは宣言だけを与えるべきです。

誰かがあなたのコードを使いたいと思っているとすれば、クラスの.hファイルと.objファイル(コンパイル後に取得)を与えることができます。彼はあなたのコードを使うのに.cppファイルは必要ありません。

あなたの実装が誰にも見えないようにします。

8

"クラス内"(I)メソッドは、 "クラス外"(O)メソッドと同じです。

ただし、クラスが1つのファイル(.cppファイル内)でのみ使用される場合は、(I)を使用できます。 (O)は、ヘッダファイル内にあるときに使用されます。 cppファイルは常にコンパイルされます。ヘッダーファイルは#include "header.h"を使用するとコンパイルされます。

ヘッダーファイルで(I)を使用すると、関数fun1は#include "header.h"をインクルードするたびに宣言されます。これにより、同じ関数を複数回宣言することができます。これはコンパイルするのが難しく、エラーにつながることさえあります。正しい使用方法について

例:

ファイル1: "Clazz.h"

//This file sets up the class with a prototype body. 

class Clazz 
{ 
public: 
    void Fun1();//This is a Fun1 Prototype. 
}; 

ファイル2: "Clazz.cpp"

#include "Clazz.h" 
//this file gives Fun1() (prototyped in the header) a body once. 

void Clazz::Fun1() 
{ 
    //Do stuff... 
} 

FILE3: "UseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz; 
MyClazz.Fun1();//This does Fun1, as prototyped in the header. 

File4: "AlsoUseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz2; 
MyClazz2.Fun1();//This does Fun1, as prototyped in the header. 

File5: "DoNotUseClazzHeader.cpp"

//here we do not include Clazz.h. So this is another scope. 
class Clazz 
{ 
public: 
    void Fun1() 
    { 
     //Do something else... 
    } 
}; 

class MyClazz; //this is a totally different thing. 
MyClazz.Fun1(); //this does something else. 
3

メンバー関数は、クラス定義内で定義することができ、または別々に::、スコープ解決演算子を使用して。インライン指定子を使用しない場合でも、クラス定義内でメンバー関数を定義すると、関数がインラインで宣言されます。だから、どちらかは、ボリューム()として、以下の関数を定義することができます

class Box 
{ 
    public: 

    double length; 
    double breadth;  
    double height;  

    double getVolume(void) 
    { 
     return length * breadth * height; 
    } 
}; 

あなたは、スコープ解決演算子を使用して、クラスの外に同じ機能を定義することができます::ここ

double Box::getVolume(void) 
{ 
    return length * breadth * height; 
} 

を次のように、重要なだけ好きならクラス:: nameの直前でクラス名を使用する必要があるということです。 ()メンバ関数は、以下の唯一のように、そのオブジェクトに関連するデータを操作するオブジェクトにドット演算子を使用して呼び出される。

Box myBox;   

myBox.getVolume(); 

(から:http://www.tutorialspoint.com/cplusplus/cpp_class_member_functions.htm) 、両方の方法が合法です。

私は専門家ではありませんが、1つのファイルにクラス定義を1つだけ入れると、それは問題ではありません。

しかし、内部クラスのようなものを適用するか、複数のクラス定義がある場合、2番目のクラスは読み込みと維持が難しいでしょう。

+0

リンクからの関連コンテンツをあなたの投稿の本文に持ち込むことができます。したがって、死んだリンクに対する未来を守ることができますか?ありがとう – JustinJDavies

1

クラス内で定義されている関数は、デフォルトではインライン関数として扱われます。 あなたが外であなたの関数を定義する必要がありますなぜ単純な理由:

仮想関数のためのクラス・チェックのコンストラクタと適切VTABLEまたはvirtual method tableを指すように仮想ポインタを初期化し、基底クラスのコンストラクタを呼び出し、の変数を初期化現在のクラスであるため、実際には動作します。

インライン関数は、関数があまり複雑でなく、関数呼び出しのオーバーヘッドを避けるために使用されます。 (オーバーヘッドには、ハードウェアレベルのジャンプと分岐が含まれています。) そして、前述のように、コンストラクタはインラインと見なされるほど簡単ではありません。

関連する問題