12

私はこれをグーグルで検索し、多くの投稿を読みましたが、非常に多くの異なる回答があり、すべてが論理的に理にかなっているため、このトピックの専門家がこの質問をわかりやすく説明できるかどうか疑問に思っていました.

戻る方法がないため、戻りがないと言う人もいます-構文が禁止しています-はい、これは理にかなっていますが、すべての関数は何かを返さなければならないと思いますか? コンストラクターは新しく作成されたオブジェクト自体を返すと言う人もいますが、コンストラクターで代入演算子が使用されているため、これは理にかなっているようです。さらに他の興味深い説明があります。

4

8 に答える 8

16

コンストラクターは他の関数のように呼び出されないため、他の関数のように戻りません。newこれらは、特定の構造 (キャスト、変数定義、ctor-initializer-list、値渡し、値渡し)の副作用として実行されます。

于 2012-04-27T18:49:12.387 に答える
11

コンストラクターは、冗長になるため、戻り値の型を指定しません。コンストラクターが潜在的に「返す」可能性がある、構築されている型以外の型はありません。技術的にはコンストラクターは何も返さないため、「return」を引用符で囲みます。静的コンテキストで呼び出されると、インスタンスを適切に初期化します。それらが動的コンテキストで呼び出されるとnew、コンストラクターではなく、何かを返すのはオペレーターです。

于 2012-04-27T18:48:17.357 に答える
8

コンストラクターはインプレースで構築され、何も返す必要はありません。

私はすべての関数が何かを返さなければならないと信じています

void?

于 2012-04-27T18:44:42.870 に答える
3

コンストラクターが何かを返す可能性があると仮定すると、これは次の関数呼び出しに問題のある影響を及ぼします。

class Object{ 
    public: 
        bool Object(){ ... };   
        ...
}      

SomeFun(Object obj){ ... } 

SomeFun(Object());   
// Ha! SomeFun jokes on an error about a non-Object argument(of type bool), returned  
// by the anonymous temporary Object()

コンストラクター関数が戻らないようにすることで、匿名の一時関数の使用が容易になり、さらに多くのC++機能が使用できるようになります。このようなルールがないと、無害なステートメントがあいまいになる可能性があります。

Object obj(Object()); 
// How does the variable obj decide which constructor to call,  
// based on its argument type?  
// 
// Does it call: bool Object::Object(Object&) or  
//                    Object::Object(bool)(if it exists)? 

コンストラクターが値を返す機能は、オブジェクトの作成を複雑にします。任意の戻り値がない場合に、単一の明確な型であるクラス名を使用すると、このような問題を回避できます。

読者は、C ++イディオムがそのようなルールの欠如によって妨げられているさらなる例を提案できますか?

于 2012-04-27T20:08:27.697 に答える
2

しかし、私はすべての関数が何かを返さなければならないと信じています、そうではありませんか?

いいえ。関数から値を返すとはどういう意味ですか?実装のABIは、あるリターンタイプに対して、関数が特定のレジスタ、またはスタックポインタからのオフセットにあるメモリを、関数によって「返される」値に設定することを指定します。

コンストラクターまたはvoid関数が呼び出された後、レジスターとメモリーが存在し、データが含まれていることは明らかですが、これらの関数は何も返さないため、ABIは、戻り値を見つけるために調べるレジスターまたはメモリーを指定しません。コードは戻り値を設定できず、呼び出し元のコードは任意の戻り値を取得できます。

したがって、関数は何も返す必要はありません。

于 2012-04-27T18:50:51.157 に答える
2

コンストラクターはおそらく悪い名前です。実際には、事前に構築されたオブジェクトの初期化子です。これを説明する最も簡単な方法は、C++ コンストラクターを使用しない同等の構成の疑似例です。

コンストラクター付き

struct X {
    int a;
    X() {
      a = -5;
    }
};

int main() {
    X* x1 = new X(); // X created as a "reference object".
    X  x2;           // X created as a "value object" on the stack.
    return x1->a - x2.a;
}

コンストラクタなし

struct X {
    int a;
    void initialize() {
        a = -5;
    }
    static X* create() {
        X* res = (X*)malloc(sizeof(X));
        res->initialize();
        return res;
    }
};

int main() {
    X* x1 = X::create(); // New constructed heap-allocated X
    X  x2;               // Stack-allocated X
    x2.initialize();     // Manually initialized
    return x1->a - x2.a;
}

X::initializeここで、2 番目の例で、たとえばbool成功または失敗を示して返されると想像すると、問題が発生します。ではmain()、注意を怠ったプログラマXは が正しく初期化されず、未定義の動作につながる可能性があります (通常、本番環境の前に発見されない可能性がある、デバッグが困難なクラッシュです)。

これが、コンストラクターが特別な理由の 1 つです。コンストラクターを終了する唯一の 2 つの方法は、通常の完了または例外によるものであり、呼び出し元によって処理される (またはスタックに渡される)必要があります。いずれにせよ、初期化されていないオブジェクトで終わるのを防ぎます。

補足として、初期化されていないオブジェクトは、C のバグのより一般的な原因の 1 つであり、このようなプログラマーを支援するものは何もありません。

于 2012-04-28T06:57:46.493 に答える
2

コンストラクターに戻り値の型voidがないということは、C++ コードからコンストラクターを呼び出すことができないことを意味します。そしてそれがポイントです。コンストラクターの呼び出しは意味がありません。コンストラクターの呼び出しを違法にすると、この種のユーザー エラーが発生する可能性がまったくなくなります。

編集

コンストラクターを呼び出せない究極の理由は、コンストラクターに名前がないことです。(そして、これでも、配置 new を介して間接的にコンストラクターを呼び出すことができることは無視されます。)

再試行:

コンストラクターには名前がないため、C++ コードからコンストラクターを呼び出すことはできません。コンストラクターが戻り値の型を持たないようにすることで、コンストラクターは他の関数とは非常に異なる種類の関数であることがプログラマーに強調されます。コンストラクターが実際に何を返すかは、ベンダー次第です。

于 2012-04-27T18:47:39.427 に答える
0

コンストラクターは、クラス自体のインスタンスを暗黙的に返します。何かを返すように設計されていて、プログラマーがクラス自体とはまったく異なるものを返すと矛盾します。基本的に、構文は混乱します。

于 2012-04-27T21:29:32.120 に答える