C++继承中父类的构造函数和析构函数调用情况
父类构造函数调用规则
- 子类会默认调用父类的无参构造函数,且发生在子类所有代码执行之前。
原因:父类里面的一些成员可能被设置为private,导致该成员变量只能由父类自己初始化。
- 如果父类不存在无参构造函数,那子类必须显式调用父类的构造函数。
- 如果父类没有构造函数,则子类不调用父类构造函数。
对于代码:
#include<iostream>
using namespace std;
class Person {
private:
int age;
};
class Student : Person {
public:
Student() {
cout << "Student::Student()" << endl;
}
};
int main() {
Student student;
}
Student
类默认构造方法汇编代码(Visual Studio 2019平台)如下:
class Student : Person {
public:
Student() {
009C1F00 push ebp
009C1F01 mov ebp,esp
009C1F03 sub esp,0CCh
009C1F09 push ebx
009C1F0A push esi
009C1F0B push edi
009C1F0C push ecx
009C1F0D lea edi,[ebp-0CCh]
009C1F13 mov ecx,33h
009C1F18 mov eax,0CCCCCCCCh
009C1F1D rep stos dword ptr es:[edi]
009C1F1F pop ecx
009C1F20 mov dword ptr [this],ecx
009C1F23 mov ecx,offset _C3F9A43E_main@cpp (09CF029h)
009C1F28 call @__CheckForDebuggerJustMyCode@4 (09C1384h)
cout << "Student::Student()" << endl;
其中没有对于父类Person
构造方法的调用(类似call
的语句),所以父类不写构造函数时,子类不会调用父类构造函数,也即并不是编译器自动生成一个构造函数给子类调用。
父类析构函数调用规则
- 当父类和子类的析构函数都显式声明时,子类的析构函数会默认调用父类的析构函数,且会在子类的析构函数最后调用。
原因:父类中可能有一些成员变量被设置为private,那么子类继承下来的这些成员变量必须由父类自己来释放。
- 当父类的析构函数不显式声明时,子类不会调用父类的构造方法。
对于代码:
#include<iostream>
using namespace std;
class Person {
private:
int age;
};
class Student : Person {
public:
Student() {
cout << "Student::Student()" << endl;
}
~Student()
{
cout << "Student::~Student()" << endl;
}
};
int main() {
// student在栈空间定义,用大括号限定其生命周期,便于看到析构函数的调用。
{
Student student;
}
}
Student
类析构函数汇编代码(Visual Studio 2019平台)如下:
~Student()
{
002221C0 push ebp
002221C1 mov ebp,esp
002221C3 push 0FFFFFFFFh
002221C5 push 2274A0h
002221CA mov eax,dword ptr fs:[00000000h]
002221D0 push eax
002221D1 sub esp,0CCh
002221D7 push ebx
002221D8 push esi
002221D9 push edi
002221DA push ecx
002221DB lea edi,[ebp-0D8h]
002221E1 mov ecx,33h
002221E6 mov eax,0CCCCCCCCh
002221EB rep stos dword ptr es:[edi]
002221ED pop ecx
002221EE mov eax,dword ptr [__security_cookie (022C004h)]
002221F3 xor eax,ebp
002221F5 push eax
002221F6 lea eax,[ebp-0Ch]
002221F9 mov dword ptr fs:[00000000h],eax
002221FF mov dword ptr [this],ecx
00222202 mov ecx,offset _C3F9A43E_main@cpp (022F029h)
00222207 call @__CheckForDebuggerJustMyCode@4 (0221384h)
cout << "Student::~Student()" << endl;
0022220C mov esi,esp
0022220E push offset std::endl<char,std::char_traits<char> > (022103Ch)
00222213 push offset string "Student::~Student()" (0229BE4h)
00222218 mov eax,dword ptr [__imp_std::cout (022D0D4h)]
0022221D push eax
0022221E call std::operator<<<std::char_traits<char> > (02211AEh)
00222223 add esp,8
00222226 mov ecx,eax
00222228 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (022D0A0h)]
0022222E cmp esi,esp
00222230 call __RTC_CheckEsp (0221294h)
}
可以看出,在最后并没有调用父类的析构函数。