一、全局变量、静态变量和局部变量
全局变量在程序开始时调用构造函数、在程序结束时调用析构函数。 静态变量在所在函数第一次被调用时调用构造函数、在程序结束时调用析构函数,只调用一次。 局部变量在所在的代码段被执行时调用构造函数,在离开其所在作用域(大括号括起来的区域)时调用析构函数。可以调用任意多次。
下面我们通过代码进行更详细的讲解:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "+ Constructor of A\n";
}
~A()
{
cout << "- Destructor of A\n";
}
};
class B
{
public:
B()
{
cout << "+ Constructor of B\n";
}
~B()
{
cout << "- Destructor of B\n";
}
};
class C
{
public:
C()
{
cout << "+ Constructor of C\n";
}
~C()
{
cout << "- Destructor of C\n";
}
};
A global;
void function()
{
cout << "Beginning of function.\n";
static B static_object;
{
C local_object;
}
cout << "End of function.\n";
}
int main()
{
cout << "Call function for 3 times ---------------\n";
for(int i = 1; i < 4; ++i) function();
cout << "Main function exiting -------------------\n";
return 0;
}
执行结果如下:
+ Constructor of A
Call function for 4 times ---------------
Beginning of function.
+ Constructor of B
+ Constructor of C
- Destructor of C
End of function.
Beginning of function.
+ Constructor of C
- Destructor of C
End of function.
Beginning of function.
+ Constructor of C
- Destructor of C
End of function.
Main function exiting -------------------
- Destructor of B
- Destructor of A
首先,对于全局变量A global ,它在程序开始时被调用,在程序结束时被析构。 其次,对于静态变量static B static_object ,它在function 第一次被调用时被构造,在程序结束时被析构。 然后,对于局部变量C local_object ,每次函数执行到它那一步时都被调用,在它所在的大括号结束时被析构,而不是在函数末尾被析构。
我们可以总结出一个规律:每次调用析构函数时总是析构最近被构造的、且没有被析构的对象。也就是:先被构造的对象后被析构,析构顺序恰与构造顺序相反。熟悉数据结构的童鞋应该可以看出这就是一种栈的模型。
二、基类、派生类和成员变量(子对象类)
如果一个类继承了很多类,它又有很多成员对象,那么其构造函数的执行是极为复杂的。我们用代码举例子。
#include <iostream>
using namespace std;
class Base1
{
public:
Base1()
{
cout << "+ Constructor of Base1\n";
}
~Base1()
{
cout << "- Destructor of Base1\n";
}
};
class Base2
{
public:
Base2()
{
cout << "+ Constructor of Base2\n";
}
~Base2()
{
cout << "- Destructor of Base2\n";
}
};
class Member1
{
public:
Member1()
{
cout << "+ Constructor of Member1\n";
}
~Member1()
{
cout << "- Destructor of Member1\n";
}
};
class Member2
{
public:
Member2()
{
cout << "+ Constructor of Member2\n";
}
~Member2()
{
cout << "- Destructor of Member2\n";
}
};
class Derived: public Base2, public Base1
{
public:
Member2 m2;
Member1 m1;
Derived(): m1(), m2(), Base1(), Base2()
{
cout << "+ Constructor of Derived\n";
}
~Derived()
{
cout << "- Destructor of Derived\n";
}
};
int main()
{
Derived d;
return 0;
}
执行结果:
+ Constructor of Base2
+ Constructor of Base1
+ Constructor of Member2
+ Constructor of Member1
+ Constructor of Derived
- Destructor of Derived
- Destructor of Member1
- Destructor of Member2
- Destructor of Base1
- Destructor of Base2
结论:
- 先调用基类的构造函数
- 再调用子对象类(成员变量)的构造函数
- 最后调用派生类的构造函数
- 调用顺序与派生类构造函数冒号后面给出的初始化列表(
Derived(): m1(), m2(), Base1(), Base2() )没有任何关系,按照继承的顺序和变量再类里面定义的顺序进行初始化。 先继承Base2 ,就先构造Base2 。先定义m2 ,就先构造m2 。 - 析构函数调用顺序仍然与构造函数构造顺序相反。
(这一段有点绕,可以暂停思考一下)
那么我们岂不是可以把两部分结合一下?出一道毒瘤C++题? 例 写出下面的程序的输出。
#include <iostream>
using namespace std;
class Base1
{
public:
Base1()
{
cout << "+ Constructor of Base1\n";
}
~Base1()
{
cout << "- Destructor of Base1\n";
}
};
class Base2
{
public:
Base2()
{
cout << "+ Constructor of Base2\n";
}
~Base2()
{
cout << "- Destructor of Base2\n";
}
};
class Member1
{
public:
Member1()
{
cout << "+ Constructor of Member1\n";
}
~Member1()
{
cout << "- Destructor of Member1\n";
}
};
class Member2
{
public:
Member2()
{
cout << "+ Constructor of Member2\n";
}
~Member2()
{
cout << "- Destructor of Member2\n";
}
};
class Derived: public Base2, public Base1
{
public:
Member2 m2;
Member1 m1;
Derived(): m1(), m2(), Base1(), Base2()
{
cout << "+ Constructor of Derived\n";
}
~Derived()
{
cout << "- Destructor of Derived\n";
}
};
Derived global;
void function()
{
static Member1 m1;
{
Base2 b2;
Base1 b1;
}
static Member2 m2;
}
int main()
{
for(int i = 1; i < 4; ++i) function();
return 0;
}
答案:
+ Constructor of Base2
+ Constructor of Base1
+ Constructor of Member2
+ Constructor of Member1
+ Constructor of Derived
+ Constructor of Member1
+ Constructor of Base2
+ Constructor of Base1
- Destructor of Base1
- Destructor of Base2
+ Constructor of Member2
+ Constructor of Base2
+ Constructor of Base1
- Destructor of Base1
- Destructor of Base2
+ Constructor of Base2
+ Constructor of Base1
- Destructor of Base1
- Destructor of Base2
- Destructor of Member2
- Destructor of Member1
- Destructor of Derived
- Destructor of Member1
- Destructor of Member2
- Destructor of Base1
- Destructor of Base2
(但愿我的C++期末考试不要出这种毒瘤题……)
参考:https://en.cppreference.com/w/cpp/language/constructor
|