在一个C ++案例中调用构造函数的顺序

时间:2015-02-24 21:46:53

标签: c++ constructor

#include <iostream>
struct A
{
    A(){std::cout<<"A()"<<std::endl;}
};

template<typename T>
struct B
{
    A a;
    T b;
    B(){std::cout<<"B()"<<std::endl;}
};

int main()
{
    B<B<B<int> > > Test;
    return 0;
}

调用构造函数的顺序是

A()
A()
A()
B()
B()
B()

我不知道为什么会这样。我以为这将是A B A B A B.你能解释一下为什么吗?

4 个答案:

答案 0 :(得分:2)

这实际上是直截了当的,如果它像ABABAB一样,那么如果你想从b的构造函数访问B就会遇到麻烦,因为你认为的顺序意味着第一个成员{ {1}}被实例化,然后a运行,然后ctor被初始化。实际上,每个成员首先被实例化(构造等),然后,构造函数被调用。

答案 1 :(得分:1)

这是因为必须在执行构造函数体之前初始化成员变量。请考虑以下示例:

struct A {
    int value;

    // Here we explicitly initialize 'value' with 5
    A() : value(5) { }
};

struct B {
    A a;

    B()
    {
        // This is perfectly valid and would print 5,
        // because 'a' has already been implicitly initialized
        // with its default constructor.
        std::cout << a.value;
    }
};

如果不是这种情况,您期望aB的构造函数中具有什么价值?你会遇到各种各样的问题。因此,必须在A的正文之前隐式调用B()的默认构造函数。

基本上,为了使其更明确,这就是正在发生的事情:

    // Initialize 'a' before body of constructor
    B() : a()
    {
        std::cout << a.value;
    }

答案 2 :(得分:1)

首先,让我们分析一下你的内容:

  • 您有一个Test class B<B<B<int> > >的对象,即:

    class B<B<B<int> > > {
        A a;
        B<B<int> > b;
    };
    
  • Test的第二个字段,Test.b属于class B<B<int> >,即:

    class B<B<int> > {
        A a;
        B<int> b;
    };
    
  • 然后您有Test.bTest.b.b的第二个字段,其为class B<int>,即:

    class B<int> {
        A a;
        int b;
    };
    

所以初始化的顺序是:

  • A()代表Test.a
  • A()代表Test.b.a
  • A()代表Test.b.b.a
  • 没有构造函数Test.b.b.b的类型为int且没有构造函数。
  • B<int>()代表Test.b.b
  • B<B<int> >()代表Test.b
  • B<B<B<int> > >()代表Test

不幸的是,所有三个构造函数都在输出上写了相同的东西:B(),但它们是不同类的不同构造函数。

答案 3 :(得分:0)

这是预期的行为,因为成员初始化发生在构造函数的主体之前。为了实现这一点,添加成员初始化器也很有帮助:

template<typename T>
struct B
{
    A a;
    T b;
    B()
    :
       a(),
       b()
    {
       std::cout<<"B()"<<std::endl;
    }
};

为了完全掌握执行顺序,我们添加一个虚拟整数字段。 我还添加了一个模板来显示嵌套。有关演示,请参阅http://ideone.com/KylQQb

#include <cstdio>

struct A
{
    A()
    :
    dummy(printf("Starting to construct A()\n"))
    {
        printf("Fully constructed A()\n");
    }
    int dummy;
};

template <typename T>
struct Nesting;

template <>
struct Nesting<int>
{
    constexpr static int value = 0;
};

template <template <typename> class T, typename I>
struct Nesting<T<I>>
{
        constexpr static int value = 1 + Nesting<I>::value;
};

template<typename T>
struct B
{
    int dummy;
    A a;
    T b;
    B()
    :
    dummy(printf("Starting to construct B() with nesting %d\n", Nesting<B<T>>::value)),
    a(),
    b()
    {
        printf("Fully constructed B() with nesting %d\n", Nesting<B<T>>::value);
    }
};

int main()
{
    B<B<B<int>>> Test;
    return 0;
}

这个输出将是

Starting to construct B() with nesting 3
Starting to construct A()
Fully constructed A()
Starting to construct B() with nesting 2
Starting to construct A()
Fully constructed A()
Starting to construct B() with nesting 1
Starting to construct A()
Fully constructed A()
Fully constructed B() with nesting 1
Fully constructed B() with nesting 2
Fully constructed B() with nesting 3