对于是否需要虚析构函数和原因,这样理解有问题吗?
假设对于class Base{
public:
Base(void);
~Base();
virtual void something() = 0;
};
class Derived:public Base{
public:
Derived(void);
~Derived();
void Dosomething();
};
//行为实现就不写了,假设都在这写了
int main()
{
Derived* p = new Derived;
// Base* p = new Derived;
p->Dosomething();
delete p;
return 0;
}
首先,派生类不是说你实例化一个基类指针指向子类的对象才叫派生类。
我在B站看了一个视频,说上面的代码改成"Base*指向子类对象,是派生类的一个条件" ,用类和对象比较,这明显不是一个层级,这个说法就是错的。
派生是个过程,多态是派生的结果。
在你对基类进行继承时,它的子类中只要有新的属性,和在基类同名的行为上更加细化的行为(基类的行为无法描述子类行为),那么这个子类就算是派生类。
例: 一个基类 Human ,它有一个行为 makelove,你肯定不想每次创建对象时,还要输入两个数据:名字和性别。而且编程时,难以用命名空间区分。
所以应该创建一个man派生类,和一个woman派生类。给这两个类自己独有的sex特征,和细致化的makelove行为实现,互为友元。即可makelove,嘿嘿。
我的理解是:派生类包括继承类,但继承类不一定是派生类。类似于继承类是派生类的 充分不必要条件。
我对虚析构的理解:
在我们创建一个子派生类对象时,编译器扫描代码时,编译器会和cpu读取内存一样,采用就近原理偷懒。
int main()
{
Derived* p = new Derived;
// Base* p = new Derived;
p->Dosomething();
delete p;
return 0;
}
当用基类指针 Derived* 指向派生类时:
编译器读取派生类的结构应该是:
{
↓ 基类属性;
↓ 基类行为;
↓ {
→ 子类属性;//从这里开始读代码,调用自己需要的
↓ 子类行为;
}
}
因此,不需要虚函数也可以:构造子类属性 ->构造基类属性->基类Dosomething(没实现)->找到了子类Dosomething->子类析构(编译器发现销毁的对象不是基类)->基类析构。完工。
在 delete 对象时,编译器也知道先调子类的析构方法,还要调用基类的析构方法。例如你想kill一个人,肯定也知道只摧毁他的性特征是不行的。斩草除根。
当用基类指针 Base* 指向派生类时:
编译器读取派生类的结构应该是:
{
→ 基类属性;//从这里开始读代码,调用自己需要的
↓ 基类行为;
↓ {
↓ 子类属性;
↓ 子类行为;
}
因此,用无虚函数的方法调用时:构造基类属性->构造子类属性->基类Dosomething(没实现)->找到了子类Dosomething->基类析构。
在 delete 对象时,先调用的是基类的析构。编译器就会认为,基类都被消除了,子类能不消除? 和human一样,都不是人了,肯定消失了啊?!
在我看来,virtual作用像是改变接口被调用的优先级。将基类析构降了一个优先级,当编译器读一遍发现没有别的析构函数时,才会去调用虚方法区的接口。
这个理解怎么说??
一看不是求助帖 你这个理解是错误的。 1. 文中 当用基类指针 Derived* 指向派生类时:,这个表述有问题
2. 需要再学习一下继承关系的构造与析构顺序
3. 补充学习虚函数表
4. 太长,别的没注意看
加油
页:
[1]