C++ 构造过程和析构过程
1、C++构造和析构的过程,类似于穿衣脱衣的过程。穿衣是:先穿内衣,再穿外套。脱衣是:先脱外套,再脱内衣。C++构造过程:首先调用父类构造方法,再调用子类构造方法。C++析构过程:首先调用子类析构方法,再调用父类析构方法。
2、子类不能继承父类的构造方法和析构方法,除此之外,其他的成员都能继承,包括父类的private成员,只不过子类不能访问private成员。
3、思考一下,为什么子类不能继承父类的构造方法?
想一想,构造方法是干什么的?构造方法是初始化对象的成分,创建对象。从语义上讲,父类构造方法初始化父类成分,构造父类对象。子类构造方法在父类对象的基础上,初始化子类专有成分,构造子类对象。如果子类继承父类构造方法,那么子类暴露一个接口,返回父类对象,这显然不合理。因此,子类不能继承父类的构造方法。
4、父类的成分只能在父类构造方法中初始化,子类只能初始化自己的专有成分,不能初始化父类的成分,可以在方法内赋值。子类如果初始化父类成分,编译报错:非法的成员初始化,不是基或成员。那么问题来了,子类没有继承父类的构造方法,那么子类如何初始化父类的成分呢?
5、子类不能继承父类的构造方法,但是可以调用父类的构造方法,而且必须调用父类的构造方法,确保父类成分初始化。如果没有显示调用父类的构造方法,会隐式调用父类的default构造方法。子类没有显式调用父类构造方法,父类没有提供default构造方法,编译报错:没有合适的default构造方法可用。
6、构造过程可认为:父类成员初始化列表,父类构造方法内赋值,子类成员初始化列表,子类构造方法内赋值。
7、C++析构方法能不能被继承,是有争议的。个人认为不能继承。有人说,不能继承,为什么子类可以调用。从语义上讲,为什么设计析构方法,析构方法撤销对象的成分。父类析构方法撤销父类的成分,子类构造方法撤销子类专有的成分。
8、析构方法是一种特殊的方法。主要体现在:
a、子类可以显式调用父类的析构方法;
b、子类不能隐藏父类的析构方法;
c、析构方法的重写规则不同,一般的virtual成员方法,重写要求方法名必须相同。析构方法的重写,方法名不同,分别是父类名和子类名。同时,纯虚的成员方法要求子类必须重写,父类可以不实现。纯虚的析构方法也要求子类必须重写(用户不重写,编译器会生成一个重写的析构方法),同时父类必须提供实现,因为必定要调用父类的析构方法。
9、子类构造方法必须调用父类构造方法,与此类似,子类析构方法执行完,必定调用父类的析构方法,可以认为子类析构方法执行完,创建一个对父类析构方法的调用。即使子类析构方法重写了父类的析构方法,子类析构方法执行完,还是要调用父类的析构方法。
10、那么问题来了,不管有没有重写,子类析构方法执行完,都必定要调用父类的析构方法。那么重写析构方法还有什么意义呢?
考虑,指针指向子类,指针的表面类型是父类,delete指针。如果没有重写析构方法,那么delete动作直接调用父类的析构方法,而不是先调用子类的析构方法,再调用父类的析构方法。
11、对象的析构过程可认为:第一步,子类析构方法撤销专有的成分,对于类类型,递归调用析构方法,对于内置类型不需要做什么,可认为不再使用它占用的内存;第二步,调用父类的析构方法,对于类类型,递归调用析构方法,对于内置类型,不需要做什么事,可认为不再使用它占用的内存。
12、什么时候声明析构方法为virtual呢?
当类中有virtual方法时,应该是声明析构方法为virtual,为什么?类中有virtual方法,意味着面向抽象编程,就会有父类指针指向子类对象。这种情况下,为了保证delete父类指针的时候,先调用子类析构方法(撤销子类专有成分),再调用父类析构方法(撤销父类成分),必须将父类析构方法声明为virtual。
如果类中没有virtual方法,不要声明virtual析构方法,为啥?对于virtual,编译器做了一些幕后工作,导致对象变大。