「オブジェクトコンストラクター」は「名前が「object」の関数で、タイプが「object」を返す」の短い名前ですか?


9

つまり、関数とコンストラクタの呼び出しに違いがある以上に、単語を選択するということです。「オブジェクトのコンストラクタ」という名前のオブジェクトは、「名前をobject返す型を持つ関数」という名前でもかまいませんobject

C ++では同じ関数と型名を使用できないと主張する人もいます。ただし、そのための回避策があります。C ++には特別な構文糖(コンストラクターと呼ばれます)があり、これを使用してobjecttypeを返す名前の関数を作成できますobject。ですから、コンストラクタは自立関数として見られ、使用できると思います。

ここに欠けている重要な意味上の違いはありますか?


1
コンストラクタはその型にちなんで名付けられているという事実は普遍的ではないことに注意してください:PHPはそれらを__constructと呼び、Object Pascal / DelphiはそれらをCreateと呼びます-そして私はその場合、それは単なる慣習であり、本当の違いはそれらがその定義の前に「コンストラクタ」というキーワードがあります。
IMSoP 2016

注:C ++のコンストラクターは何も返しませ(したがって、戻り値の型はありません)。
el.pescado 16

アクターはメタメソッドであり、メソッドではありません。クラスのインスタンスにctorsメッセージを送信するのではなく、クラスに送信します。実際には、クラスのメタオブジェクトであるクラスオブジェクトに送信します。また、アクターは副作用があるため、関数ではありません。毎回異なる結果が得られます。

回答:


17

コンストラクタは基本的にはメソッドですが、特別なメソッドです。

たとえば、C ++では、コンストラクターは、その型の新しいインスタンスを返す関数だけではありません。そうであれば、継承は機能しません。基本コンストラクターを呼び出すことはできませんでした。それらも新しいインスタンスを返すからです。最終的にAの新しいインスタンスが作成され、Bのコンストラクタに返されて、Bの新しいインスタンスが作成され、Cのコンストラクタに返されます。

代わりに、コンストラクターは、インスタンスアロケーターによって自動的に呼び出される初期化メソッドです。たとえば、 "new"を呼び出してヒープ上にオブジェクトを作成すると、要求された型にメモリが割り当てられ(mallocなどのメモリアロケータを使用)、そのコンストラクタメソッドが呼び出されます。コンパイラーには、そのコンストラクターが他のコンストラクターを呼び出す方法と順序について特別な規則があります。たとえば、C#では、基本コンストラクターを明示的に呼び出さない場合、コンパイラーは基本デフォルトコンストラクターへの呼び出しを追加します。

「型のインスタンスを返す.ctorという名前の関数」とは異なるコンストラクタをコンパイラがどのように処理するかについてのルールです。


3
またnew、自動変数を持っているため、C ++でオブジェクトを構築するために通常使用しません。
クエンティン

6

いいえ、のコンストラクタはobject、呼び出されobjectて返される関数とは大きく異なりobjectます。コンストラクタには名前がありませんが、それは主に技術的なことです。さらに重要な違いは、コンストラクターには戻り値の型がないことと、コンストラクターを直接呼び出すことができないことです。

コンストラクターはメモリブロックが与えられ、そのメモリをインプレースで操作するため、何も返しません「コンストラクタ」という名前を一瞬忘れて、代わりにイニシャライザと考えると役立つ場合があります。コンストラクターの目的は、「薄い空気から」オブジェクトを構築することではありません。その目的は、オブジェクトをメモリ内の必要な場所に正確に初期化することです。

コンストラクターがオブジェクトを返す場合、その返されたオブジェクト(戻り値)はどこかに(おそらくスタック上に)存在する必要があり、そこで何らかの方法で初期化する必要があります。ここでループに遭遇しています。

これは、コンストラクターを直接呼び出すことはできないという事実と関連しています。クラスがobjectあり、object()どこかで式を使用する場合、「のコンストラクターを呼び出す」というセマンティクスはありませんobjectobject「タイプの一時オブジェクトを作成する」というセマンティクスがあります。コンパイラーはこれを、一時変数が(おそらく/通常はスタック上に)存在する場所を割り当て、その場所でオブジェクトを構築(=初期化)するためにコンストラクターを呼び出すことに変換します。

同じ原理がを使用するときに適用されますnew object()。これは、次の2つのことを行う新しい式です。

  1. オブジェクトに未加工のメモリを割り当てるにoperator newは、割り当て関数(を返すvoid*)を呼び出します。
  2. このrawメモリにコンストラクター呼び出しを発行して、そのrawメモリの一部にオブジェクトを構築(=初期化)します。

のコンストラクタを次のobjectような関数と考えます。

static object object();

間違っている。どちらかといえば、コンストラクタの動作はこれに近いです:

static void object(object &place_to_work_in);

ただし、直接呼び出すことはできません。これは常に、異なる言語構造によって指定された場合にのみ呼び出されます。新しい配置(「ここでコンストラクタを呼び出す」トリックとも呼ばれます)でもnew (&place_for_object) object()、コンストラクタを直接呼び出しません。これは、placement-new形式の呼び出しに変換され、operator newその引数が返され、その後にコンストラクタが呼び出されます(他のnew-expressionと同様)。


私はこのスタックにあまり参加していないことを告白しているので、ここでは文化や期待される基準に精通していない可能性があります。この回答で改善できることがあれば、ダウン投票に加えてお知らせください。修正します。
AngewはSOを誇りに思っていません2016

+1その反対投票について心配しないでください。あなたの答えは素晴らしいです:)なんらかの理由で、ここにあるほとんどすべての回答に反対投票が1つあります。
amon、

1

言い換える試みは正しくありません。

コンストラクターはクラスの名前と同じ名前のメンバー関数のように見えますが、実際のところ、コンストラクターには実際には名前がありません。これは、C ++標準(セクション[class.ctor] / 1)で明示的に述べられています。

コンストラクターには名前がありません。

「コンストラクタは自立関数として見られ、使用できると思います」というのは...まあ、あなたの意味がよくわかりません。無料の関数は、コンストラクターにすることはできません。コンストラクターはクラスのメンバーでなければなりません。同時に、オブジェクトを作成してそのオブジェクトのインスタンスを返す無料の関数を確実に定義できます。その自由な関数は、もしあなたがひどくやりたければ、それが作成するオブジェクトのタイプと同じ名前を(ある種の)持つことさえできます。たとえば、名前空間内でクラスを定義してから、名前空間外で関数を定義できます。

namespace foo { 
    class bar {};
}

foo::bar bar() { return foo::bar(); }

これは実際には同じ名前ではありませが(関数はちょうどbarで、クラスはですfoo::bar)、視点に応じて、とにかくそれらをそのように見ることができます。

このような自由な関数には、コンストラクターの他の重要な特徴はありません。コンストラクターの呼び出しは、完全に暗黙的な場合があります。たとえば、次のようなクラスがあるとします。

class foo {
public:
   foo (int) {}
   foo operator+(foo const &other) {}
};

...次のようなコード:

foo f(1);

foo h(0);
h = f + 1;

...から一時的なfooオブジェクトを作成1できるので、そのfooオブジェクトをに渡すことができますfoo::operator+。そのフリー関数が適切なパラメーター型を取り、必要な結果の型を返すように定義されていても、それはフリー関数では起こりません。このような暗黙の変換には、コンストラクターが必要です。


1

つまり、関数とコンストラクタの呼び出しに違いがある以上に、単語を選択するということです。「オブジェクトのコンストラクタ」という名前のオブジェクトは、「名前オブジェクトが型オブジェクトを返す関数」と呼ぶこともできます。

まず、コンストラクターは何も返さず、結果として戻り値の型がありません。

次に、コンストラクターは、関数を呼び出す方法でコンストラクターを直接呼び出すことができないという点で異なります。代わりに、変数を宣言すると、ランタイムによって適切なコンストラクターが呼び出されます。

3番目に、継承の場合、サブクラスの通常の関数は親クラスの関数をオーバーライドします。一方、コンストラクタはカスケードします-親クラスのコンストラクタが最初に呼び出され、次にサブクラスのコンストラクタが呼び出されます。

4番目に、コンストラクターは初期化リストを持つことができますが、「通常の」関数はできません。

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