在一种情况下调用构造函数的顺序C++
Order of calling constructors in one case C++
#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;
}
调用构造函数的 odrer 是
A()
A()
A()
B()
B()
B()
我不知道这是为什么。我以为会是A B A B A B.你能解释一下为什么吗?
这实际上很简单,如果它像 A B A B A B,那么如果你想从 B
的构造函数访问 b
,你就会遇到麻烦,因为你认为的顺序意味着第一个成员a
被实例化,然后ctor
运行,然后b
被初始化。实际上,每个成员首先被实例化(构造等(,然后调用构造函数。
这是因为在执行构造函数的主体之前必须初始化成员变量。请考虑以下示例:
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;
}
};
如果不是这种情况,你期望a
在B
的构造函数中有什么价值?你会遇到各种各样的问题。因此,必须在 B()
的主体之前隐式调用 A
的默认构造函数。
从本质上讲,为了使它更明确,这就是正在发生的事情:
// Initialize 'a' before body of constructor
B() : a()
{
std::cout << a.value;
}
首先,让我们分析一下你在这里有什么:
-
你有一个对象
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.b
域,Test.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()
,但它们是不同类的不同构造函数。
这是预期的行为,因为成员初始化发生在构造函数的主体之前。为了实现这一点,添加成员初始值设定项也很有帮助:
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 %dn", Nesting<B<T>>::value)),
a(),
b()
{
printf("Fully constructed B() with nesting %dn", 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
相关文章:
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 确保所有构造函数调用相同的函数 c++ 设计模式
- 减少复制构造函数调用
- 使用回调函数从构造函数调用虚拟/派生方法的替代方法?
- 在 Google 测试中,我可以从构造函数调用 GetParam() 吗?
- C++ - 从另一个类构造函数调用类构造函数
- 在C++中初始化带有和不使用构造函数调用的对象有什么区别
- 是否可以从移动构造函数调用默认构造函数?
- 在模板生成器模式中分解重复的构造函数调用
- std::atexit 从全局对象的构造函数调用时的排序
- 对构造函数调用的约束
- 编译器错过了无效的构造函数调用,并调用不存在的(或私有的)默认构造函数
- 用构造函数调用填充向量
- 创建指针时是否没有构造函数调用
- 使用 emplace_back 避免移动构造函数调用的最佳方法?
- C++ 抽象类构造函数调用
- 为什么函数参数将带有参数的构造函数调用
- 为什么比“构造函数”调用更多的“解构器”调用
- 将对象传递给函数并不是导致构造函数调用