C++知识点随笔(四):耦合问题、new和malloc、虚析构、多继承

来源:互联网 发布:约瑟夫环算法 数组 编辑:程序博客网 时间:2024/04/30 09:40

一、耦合问题

即互相包含头文件的问题,解决方法:
1. 在一个类的头文件里声明另一个类,那么我们在定义的时候就不能new对象,但是可以定义一个指针。这只是为了保证编译通过,等到具体创建对象的时候还是会使用原来的类成员。
2. 可以抽象出一个父类,让这个父类里面同时包含这两个子类里需要耦合的部分。
3. friend方法,其实也相当于一个声明,但是friend会破坏类的封装性。(传说中友元是不需要头文件的)。
4. 降低耦合性参考:http://developer.178.com/200912/54167815997.html

二、new和malloc的区别

malloc只是在堆区申请空间;
而new里面封装了三件事情:
1. 调用类的构造函数
2. 在堆区申请空间
3. 返回对象的首地址

delete封装了两件事:
1. 调用析构函数
2. 删除指针所指向的全部空间
注意:delete删除空间时一定将new的对象大小全部删除了,但是调用谁的析构就要看这个指针本身的类型了。所以当这种情况时:

CFather *son = new CSon;delete son;

就不会调用子类的析构函数,从而可能会造成内存泄露。所以要解决这个问题,就有了我们后面的虚析构的诞生。

三、虚析构

虚析构就是当我们delete父类指针的时候,会首先调用子类的析构函数,然后再调用父类的析构函数,这样就保证了所有的子类析构函数都可以调用,从而避免了内存泄露的问题。它的形式是这样的:

virtual ~CFather();

什么时候用虚析构呢?
有多态或者说有virtual的时候就用虚析构。这个虚析构同样也存在于虚函数列表中,子类的析构函数会重写这个表中的虚析构函数指针。注意:虚析构函数指针不一定就在虚函数列表的最后,它和普通虚函数一样,是根据父类中声明的顺序加入虚函数列表的。

为什么调用子类的析构函数之后一定会调用父类的析构函数?
我们之前讲过,子类继承父类的过程其实相当于在最开始的时候定义了一个父类的对象,那么当我们执行完子类的析构函数之后,这个子类就要回收了,所以定义的父类的对象的作用域也就结束了,就会自动调用父类对象的析构函数了。

四、多继承

多继承形式:

class AA : public BB, public CC

多继承的构造顺序是:BB->CC->AA
多继承的所以父类中,从左向右依次执行构造函数。
多继承的缺点:
多继承会出现访问不明确的问题,因为多继承是这样的:
这里写图片描述
所以有两份AA,这样我们在使用AA的成员变量的时候就会发生访问不明确的问题,解决的方法就是使用虚继承,这个我们后面再讲。
另外当我们多继承的父类,即BB和CC同时拥有两个同名的虚函数时,子类也无法将他们重写,还是指向不明确的问题,这个问题我们可以通过嵌套类来解决,后面再讲。
其实多继承的出现本身就是一种缺陷,证明了我们的程序设计的不够完美,所以我们在程序设计的时候尽量避免多继承的出现。

0 0