違いは何ですか?
Display *disp = new Display();
そして
Display *disp;
disp = new Display();
そして
Display* disp = new Display();
そして
Display* disp(new Display());
最初のケース:
Display *disp = new Display();
3つのことを行います:
Display*
の新しい変数disp
、つまりタイプDisplay
のオブジェクトへのポインターを作成し、次にDisplay
オブジェクトを割り当て、disp
オブジェクトを指すようにDisplay
変数を設定します。2番目の場合:
Display *disp; disp = new GzDisplay();
タイプDisplay*
の変数disp
を作成してから、ヒープ上に別のタイプ、GzDisplay
のオブジェクトを作成し、そのオブジェクトを割り当てます。 disp
変数へのポインター。
これは、GzDisplayがDisplayのサブクラスである場合にのみ機能します。この場合、 ポリモーフィズム の例のように見えます。
また、あなたのコメントに対処するために、宣言の間に違いはありません:
Display* disp;
そして
Display *disp;
ただし、Cタイプのルールの動作方法により、次の点で違いがあります。
Display *disp1;
Display* disp2;
そして
Display *disp1, disp2;
その最後の場合、disp1
はDisplay
オブジェクトへのポインタであり、おそらくヒープに割り当てられているのに対し、disp2
はおそらくスタックに割り当てられた実際のオブジェクト。つまり、ポインターは間違いなく型の一部ですが、パーサーは代わりにそれを変数に関連付けます。
// implicit form
// 1) creates Display instance on the heap (allocates memory and call constructor with no arguments)
// 2) creates disp variable on the stack initialized with pointer to Display's instance
Display *disp = new Display();
// explicit form
// 1) creates Display instance on the heap (allocates memory and call constructor with no arguments)
// 2) creates disp variable on the stack initialized with pointer to Display's instance
Display* disp(new Display());
// 1) creates uninitialized disp variable on the stack
// 2) creates Display instance on the heap (allocates memory and call constructor with no arguments)
// 3) assigns disp with pointer to Display's instance
Display *disp;
disp = new Display();
初期化の明示的形式と暗黙的形式の違いは、コンストラクターを持つ複合型でのみ見られます。ポインタタイプ(表示*)の場合、違いはありません。
明示的な形式と暗黙的な形式の違いを確認するには、次のサンプルを確認してください。
#include <iostream>
class sss
{
public:
explicit sss( int ) { std::cout << "int" << std::endl; };
sss( double ) { std::cout << "double" << std::endl; };
// Do not write such classes. It is here only for teaching purposes.
};
int main()
{
sss ddd( 7 ); // prints int
sss xxx = 7; // prints double, because constructor with int is not accessible in implicit form
return 0;
}
Display *disp = new Display();
このコード行は、Display *型の変数を作成し、新しく作成されたオブジェクトのアドレスで初期化します。
Display *disp; // (1)
disp = new Display(); // (2)
コードの最初の行は、Display *型の変数を宣言するだけです。コンパイラの設定に応じて、ポインタが初期化される場合とされない場合があります。基本的には、NULLを指す必要のない無効なポインタとして扱う必要があります。
2行目は、新しく作成されたオブジェクトのアドレスをポインタに割り当てます。
両方のコードスニペットの結果は同じになります。
最適化を有効にすると、コンパイラは両方に対して同じアセンブリを生成する必要があります。最適化を無効にし、一部のデバッグコード生成(両方のスニペットがまったく異なるコードを生成する可能性があります)を使用すると、2番目のケースでは、ポインターは最初に、コンパイラーが初期化されていないポインター(0xDEADBEEF、0xEFEFEFEFなど)に使用する値で初期化され、簡単に認識できますパターン)。最初のスニペットでは、設定に関係なく、ポインタは常にオブジェクトのアドレスに初期化される必要があります。これはコンパイラに依存することに注意してください-私が言うようにコンパイラによっては、まったく異なることをする場合があります。
同じことを書く4つの方法を見つけました。
例1(Display *disp…
)と3(Display* disp…
)は同じです。 *
の周りの間隔は重要ではありません。ただし、次の理由から、スタイル1が好まれることがよくあります。
Display* disp1, disp2;
実際には:
Display *disp1, disp2;
つまり、disp2はポインタではありません。
例2(2行に分割)は同じ効果があり、おそらく同じコードにコンパイルされます。初期化構文を使用する4番目の例でも、同じことが行われます。
これらがポインタではなくクラスである場合、動作と速度に違いがある可能性があることに注意してください。
タイプDisplay
のオブジェクトとタイプGzDisplay
のオブジェクトを作成しますが、これは意図的なものですか、それともタイプミスですか?
タイプミスの場合、生成されるコードに関して違いはありませんが、変数disp
がスコープ内にあり、初期化されていない時間はないため、最初の方法が推奨されます。
1)GzDisplayのインスタンスは2番目のバリアントで作成されますが、1番目のバリアントでは、作成されたインスタンスはDisplayタイプです(GzDisplayはDisplayのサブクラスだと思いますよね?)。 2)1番目が短いことに加えて、2番目のdispには、新しいGzDisplay()が割り当てられるまで未定義の値があります。 2番目のバリアントは、誤ってそれを忘れて、初期化する前にdispを使用するコードを挿入する機会を与えます。