子类的构造函数必须对继承而来的成员进行初始化
1.直接通过初始化列表或者赋值的方式进行初始
2.调用父类构造函数进行初始化
父类构造函数在子类中的调用方式
1.默认调用.适用无参构造函数和使用默认参数的构造函数
2.显示调用.通过初始化列表进行调用,适用于所有父类的构造函数
例子:
class Child : public parent
{
public:
Child()/*隐式调用,调用父类无参构造函数和默认参数的构造函数,如果父类没有该类型的构造函数则报错*/
{
cout<<"Child()"<<endl;
}
Child(string s) : Parent("Parameter to Parent")/*显示调用,通过初始化列表进行调用*/
{
cout<<"Child(): "<<s<<endl;
}
}
看下面这个例子:
#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
Parent()
{
cout<<"Parent ()"<<endl;
}
Parent(string s)
{
cout<<"Parent(string s)"<<s<<endl;
}
};
class Child : Parent
{
public:
Child()
{
cout << "Child()" <<endl;
}
Child(string s)
{
cout<<"Child(string s): "<<s<<endl;
}
};
int main()
{
Child c;
Child c1("c1");
return 0;
}
结果:
Parent ()
Child()
Parent ()
Child(string s): c1
因为Child c,Child c1(“c1”)都是隐式调用,调用父类无参构造函数或者默认参数的构造函数,而父类中只有Parent()这个无参构造函数,所以先调用父类的无参构造函数再调用本类的构造函数
代码改动:
class Child : Parent
{
public:
Child()
{
cout << "Child()" <<endl;
}
Child(string s) : Parent(s)
{
cout<<"Child(string s): "<<s<<endl;
}
};
结果:
sice@sice:~$ ./a.out
Parent ()
Child()
Parent(string s)c1
Child(string s): c1
现在 Child c1(“c1”)成了显示调用,所以调用了父类的参数一致的构造函数,现在我们可以得出一套构造规则
构造规则:
子类对象在创建时会首先调用父类的构造函数
先执行父类构造函数再执行子类的构造函数
父类构造函数可以被隐式调用或者显示调用
补充:对象创建时构造函数的调用顺序
1.调用父类的构造函数
2.调用成员变量的构造函数
3.调用类自身的构造函数
例子:
#include <iostream>
#include <string>
using namespace std;
class Object
{
public:
Object(string s)
{
cout << "Object (string s)"<<s<<endl;
}
};
class Parent: public Object
{
public:
Parent():Object("default")
{
cout<<"Parent ()"<<endl;
}
Parent(string s):Object(s)
{
cout<<"Parent(string s)"<<s<<endl;
}
};
class Child :public Parent
{
Object mO1;
Object mO2;
public:
Child():mO1("default 1"),mO2("default 2")
{
cout << "Child()" <<endl;
}
Child(string s) : Parent(s),mO1(s + "1"),mO2( s + "2")
{
cout<<"Child(string s): "<<s<<endl;
}
};
int main()
{
//Child c;
Child c1("c1");
return 0;
}
结果:
sice@sice:~$ ./a.out
Object (string s)c1
Parent(string s)c1
Object (string s)c11
Object (string s)c12
Child(string s): c1
可以看出父类的调用最先,就是Parent的构造函数,接着"客人"mO1(s + “1”),mO2( s + “2”),最后是自己的构造函数
析构函数的调用顺序与构造函数相反
1.执行自身的析构函数
2.执行成员变量的析构函数
3.执行父类的析构函数
例子:
#include <iostream>
#include <string>
using namespace std;
class Object
{
string ms;
public:
Object(string s)
{
cout << "Object(string s) : " << s << endl;
ms = s;
}
~Object()
{
cout << "~Object() : " << ms << endl;
}
};
class Parent : public Object
{
string ms;
public:
Parent() : Object("Default")
{
cout << "Parent()" << endl;
ms = "Default";
}
Parent(string s) : Object(s)
{
cout << "Parent(string s) : " << s << endl;
ms = s;
}
~Parent()
{
cout << "~Parent() : " << ms << endl;
}
};
class Child : public Parent
{
Object mO1;
Object mO2;
string ms;
public:
Child() : mO1("Default 1"), mO2("Default 2")
{
cout << "Child()" << endl;
ms = "Default";
}
Child(string s) : Parent(s), mO1(s + " 1"), mO2(s + " 2")
{
cout << "Child(string s) : " << s << endl;
ms = s;
}
~Child()
{
cout << "~Child() " << ms << endl;
}
};
int main()
{
Child cc("cc");
cout << endl;
return 0;
}
Object(string s) : cc
Parent(string s) : cc
Object(string s) : cc 1
Object(string s) : cc 2
Child(string s) : cc
~Child() cc
~Object() : cc 2
~Object() : cc 1
~Parent() : cc
~Object() : cc
可以看出析构顺序与构造顺序对称相反
要点:
子类对象在创建的时候需要调用父类构造函数进行初始化
先执行父类构造函数然后执行成员的构造函数
!!父类构造函数显示调用需要在初始化列表中进行!!
子类对象在销毁时需要调用父类析构函数进行清理