2

次のコードを検討してください。

class A {
public:
    int a;
};

class B : public A {
public:
    B() { std::cout << "B[" << a << "]" << std::endl; }
};

class C : public B {
public:
    C() { std::cout << "C[" << a << "]" << std::endl; }
};

int main(int argc, char *argv[]) {

    B();
    std::cout << std::endl;
    C();

}

そしてその出力-g++でコンパイルされたプログラム(Ubuntu / Linaro 4.6.3-1ubuntu5)4.6.3:

B[0]

B[-2097962768]
C[-2097962768]

2番目の呼び出しを取得するために私が見つけた唯一の方法---C()その値を初期化するために、コンストラクターに次のような明示的な呼び出しを追加することでした。

class B : public A {
public:
    B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};

class C : public B {
public:
    C() : B() { std::cout << "C[" << a << "]" << std::endl; }
};

以前の各クラスのデフォルトコンストラクターを呼び出すと値が初期化されることは理解していますが、何も指定されていない場合に何が呼び出されているかを確認できません。

デフォルトのコンストラクターはデフォルトで呼び出されるものではありません-したがって、そのハンドルですか?

4

2 に答える 2

6

元のコードで

class A {
public:
    int a;
};

class B : public A {
public:
    B() { std::cout << "B[" << a << "]" << std::endl; }
};

A初期化を指定していないため、のメンバーは初期化されません。そして一般的に、C++では必要のないものにお金を払うことはありません。したがって、PODメンバーの初期化はデフォルトでは取得されません(ただし、初期化が指定されているため、コンストラクターを持つメンバーの初期化は取得されます)。

後続の「明示的なコンストラクター呼び出し」コードで

class B : public A {
public:
    B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};

基本クラスサブオブジェクトの値の初期化を指定しました。A事実上、これはゼロ初期化に減少します。

と同じ違いです

A* p = new A;

A* p = new A();

後者の値-オブジェクトを初期化します。


標準的な…

C++11§8.5/10
「初期化子が空の括弧のセットであるオブジェクト、つまり、()は値で初期化されるものとします。」

C++11§8.5。/7
「タイプのオブジェクトを値で初期化Tするということは、次のことを意味します
。—Tユーザー提供のコンストラクター(12.1)を使用する(おそらくcv修飾された)クラスタイプ(条項9)の場合、デフォルトのコンストラクターTが呼び出されます(Tアクセス可能なデフォルトのコンストラクターがない場合、初期化の形式が正しくありません)。
Tが(おそらくcv修飾された)非ユニオンクラスタイプであり、ユーザー提供のコンストラクターがない場合、オブジェクトはゼロで初期化され、Tの暗黙的に宣言されたデフォルトコンストラクターが自明でない場合、そのコンストラクターが呼び出されます。
Tが配列型の場合、各要素は値で初期化されます。
—それ以外の場合、オブジェクトはゼロで初期化されます。
値が初期化されたオブジェクトは構築されたと見なされるため、オブジェクトのコンストラクターが呼び出されない場合でも、「構築された」オブジェクト、「コンストラクターが完了した」オブジェクトなどに適用されるこの国際規格の規定の対象となります。初期化。」

値の初期化が元のC++98の一部ではなかったことはおそらく注目に値します。これは、純粋なデフォルト初期化の予期しない影響のいくつかの深刻な問題に対処するために、Andrew Koenig(「Koeniglook-up」の名声)によってC++03で導入されました。これは、()イニシャライザーがC++98で購入したものです。

于 2013-02-26T15:48:02.777 に答える
3

私の元の答えを編集するのはかなり間違っていたので、私はそれを大幅に編集しました。

A::a次のような値の初期化呼び出しがない場合にゼロで初期化されることを保証したい場合

A a1; //

また

B() { .... }

次にA、コンストラクターを指定して、そこで初期化を行うことができます。

class A {
public:
  A() : a() {} // value initialization of a, means zero initialization here.
    int a;
};

A()それ以外の場合は、Bおよびのコンストラクターを明示的に呼び出すとC、値の初期化が実行されます。

// value initialization of A sub-object leads to zero initialization of A::a
 B() : A() {} 

これは、Aインスタンスの初期化でも機能します。

A a1 = A();
于 2013-02-26T15:31:45.380 に答える