今天在开发时遇到了一个之前一直以为理所当然的构造函数问题。
先给总结:
子类在构造时,如果没有显式调用父类的构造函数,会先调用父类的默认构造函数(无参数的)
下面给出不同情况的例子
例子一:父类有默认的构造函数,子类的构造函数随便
#include <iostream> class Base{ public: Base(){ } }; class Derive:public Base{ public: Derive(int a,int b){ } }; int main(){ Derive c(1,2); return 0; }
结果:编译通过,暂时不能说明问题。
例子二:父类没有默认的构造函数,子类的构造函数随便
#include <iostream> class Base{ public: Base(int a){ } }; class Derive:public Base{ public: Derive(int a,int b){ } }; int main(){ Derive c(1,2); return 0; }
结果:编译错误,错误信息:[Error] no matching function for call to ‘Base::Base()‘
说明,子类的构造需要先调用父类的默认构造函数
例子三:父类没有默认的构造函数,子类的构造函数随便,但是显式调用了父类的构造函数
#include <iostream> class Base{ public: Base(int a){ } }; class Derive:public Base{ public: Derive(int a,int b):Base(a){ } }; int main(){ Derive c(1,2); return 0; }
结果:编译成功
说明,显式调用父类的构造函数之后,不再调用父类的默认构造函数
例子四:父类没有默认的构造函数,子类的构造函数与父类的参数列表相同,但是没有显式调用父类的构造函数
#include <iostream> class Base{ public: Base(int a){ } }; class Derive:public Base{ public: Derive(int a){ } }; int main(){ Derive c(1); return 0; }
结果:编译错误
说明,其实这种情况跟例子二的情况是一样的,只不过父类跟子类的构造函数参数一样,所以会给人感觉子类会调用父类相同参数的构造函数,但其实子类还是先调用父类的默认构造函数的。由于父类没有默认的构造函数,所以编译错误,错误信息跟例子二一样。
例子五(陷阱):父类跟子类的构造函数有相同的参数,且父类有默认的构造函数。子类没有显式调用父类的构造函数。
#include <iostream> class Base{ public: Base(int a){ this->a = a; } Base(){ } public: int a; }; class Derive:public Base{ public: Derive(int a){ } }; int main(){ Derive c(1); std::cout << c.a << std::endl; return 0; }
结果:编译成功,运行输出结果为:3674912
说明,这种情况跟例子四如出一辙,只不过由于父类有默认的构造函数,所以才会编译成功。子类的带一个int参数的构造函数并没有调用父类带一个int参数的构造函数。
最后,再来一次总结:上面五个例子说明了,如果子类的构造函数中没有显式调用父类的构造函数,则先默认调用父类的默认构造函数。
换句话说,在使用继承时,如果父类没有默认的构造函数,则子类的构造函数应当显式地调用父类的自定义构造函数。