首先调用哪个构造函数
Which constructor is called first
下面的代码来自。作者试图告诉我们,通过将所有东西都变成对象,我们可以防止资源泄漏。我的问题:为什么"cat"answers"dog"的构造函数比"userresources"的构造函数更早被调用?
//: C07:Wrapped.cpp
// Safe, atomic pointers
#include <fstream>
#include <cstdlib>
using namespace std;
ofstream out("wrapped.out");
// Simplified. Yours may have other arguments.
template<class T, int sz = 1> class PWrap {
T* ptr;
public:
class RangeError {}; // Exception class
PWrap() {
ptr = new T[sz];
out << "PWrap constructor" << endl;
}
~PWrap() {
delete []ptr;
out << "PWrap destructor" << endl;
}
T& operator[](int i) throw(RangeError) {
if(i >= 0 && i < sz) return ptr[i];
throw RangeError();
}
};
class Cat {
public:
Cat() { out << "Cat()" << endl; }
~Cat() { out << "~Cat()" << endl; }
void g() {}
};
class Dog {
public:
void* operator new[](size_t sz) {
out << "allocating an Dog" << endl;
throw int(47);
}
void operator delete[](void* p) {
out << "deallocating an Dog" << endl;
::delete p;
}
};
class UseResources {
PWrap<Cat, 3> Bonk;
PWrap<Dog> Og;
public:
UseResources() : Bonk(), Og() {
out << "UseResources()" << endl;
}
~UseResources() {
out << "~UseResources()" << endl;
}
void f() { Bonk[1].g(); }
};
int main() {
try {
UseResources ur;
} catch(int) {
out << "inside handler" << endl;
} catch(...) {
out << "inside catch(...)" << endl;
}
} ///:~
为什么'cat'和'dog'的构造函数比' userresources '的构造函数更早被调用?
在UseResources
的构造函数体输入之前被调用。
UseResources
有两个数据成员,它们是PWrap<>
类模板的实例化。PWrap<T>
的构造函数实例化了一些T
类型的对象:
ptr = new T[sz];
从而导致对T
(在您的示例中为Cat
或Dog
)的构造函数的相应次数的调用。
由于PWrap
对象是UseResources
的数据成员,它们的构造函数在进入UseResources
构造函数体之前执行。这就是c++中对象构造的工作方式。
这样做的基本原理是确保在进入构造函数体时,所有子对象(包括基子对象和成员子对象——如Bonk
和Og
)的构造函数都已完成。
这样,构造函数可以依赖于使用有效的子对象,这些子对象的类不变式在执行时已经建立。
c++ 11标准第12.6.2/10段是这样描述这个过程的:
在非委托构造函数中,初始化按照以下顺序进行:
-首先,并且仅对最派生类的构造函数(1.8)初始化虚基类它们在基类的有向无环图从左到右的深度优先遍历中出现的顺序,其中"从左到右"是派生类基-指定符列表中基类的出现顺序。
-然后,直接基类按照它们出现在base-specifier-list中的声明顺序初始化(不管初始化式的顺序如何)
- 然后,按照在类定义中声明的顺序初始化非静态数据成员.
- 最后,执行构造函数体的复合语句。
[注意:强制声明顺序以确保基和成员子对象在初始化的相反顺序。- 结束说明]
调用构造函数的顺序为:
- 基类
- 。
- 成员,按顺序出现在标题
- 类的构造函数。
类userresources在构造函数体被调用之前被"构造",因为它有一个大小,并且成员变量有适当的地址。然而,它们还没有完全构建。
构造函数体可以假设它的所有成员都已经被完全构造(调用了它们的构造函数),因此必须按这个顺序调用它们。
因此,Bonk和Og的构造函数在userresources之前按此顺序调用。
代码段:
UseResources() : Bonk(), Og() {
out << "UseResources()" << endl;
}
实际上你是在构造Bonk和Og成员之前调用userresources构造函数,但只是稍后输出你的日志
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 确保所有构造函数调用相同的函数 c++ 设计模式
- 减少复制构造函数调用
- 使用回调函数从构造函数调用虚拟/派生方法的替代方法?
- 在 Google 测试中,我可以从构造函数调用 GetParam() 吗?
- C++ - 从另一个类构造函数调用类构造函数
- 在C++中初始化带有和不使用构造函数调用的对象有什么区别
- 是否可以从移动构造函数调用默认构造函数?
- 在模板生成器模式中分解重复的构造函数调用
- std::atexit 从全局对象的构造函数调用时的排序
- 对构造函数调用的约束
- 编译器错过了无效的构造函数调用,并调用不存在的(或私有的)默认构造函数
- 用构造函数调用填充向量
- 创建指针时是否没有构造函数调用
- 使用 emplace_back 避免移动构造函数调用的最佳方法?
- C++ 抽象类构造函数调用
- 为什么函数参数将带有参数的构造函数调用
- 为什么比“构造函数”调用更多的“解构器”调用
- 将对象传递给函数并不是导致构造函数调用