虚析构与虚函数

本文探讨了虚析构与虚函数在C++中的作用,包括如何避免内存泄露、正确调用派生类的方法。通过实例演示了虚函数和非虚函数在析构和函数调用时的不同行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

虚析构与虚函数

1)当我们释放一个子类对象 delete derive;先调用子类析构函数,再调用父类析构函数
当我们释放一个指向子类的父类指针 base *p=new derive;delete p;若父类析构函数没有声明为虚函数,在delete p调用析构函数时,只会看指针的数据类型,而不会去看赋值的对象,这样就会造成内存泄露,即只执行父类的析构函数,不执行子类的析构函数;
因此当需要使用基类对派生类的对象操作时,如父类指针指向子类对象,需要将父类析构函数声明为虚,这样delete p时,先调用子类析构,再调用父类析构。
2)当我们调用一个子类对象的函数derive->func,则直接调用子类对象的func函数;
当我们通过父类指针指向子类对象调用函数 base *p=new derive;p->func,若func没有声明为虚,则只会看指针的数据类型,而不会去看赋值的对象,调用父类的func函数;
因此当需要使用基类对派生类的对象操作时,如父类指针指向子类对象,需要将父类函数声明为虚,这样调用函数时,调用的就是子类的func函数。

如果把子类析构想象成一个函数,其功能为先析构子类再析构父类,则上述1)2)完全一致

但是仍然存在不同之处:

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
	A()
	{
		cout << "a的构造" << endl;
	}
	virtual void func()
	{
		cout << "a的func" << endl;
		func2();
	}
	virtual void func2()
	{
		cout << "a的func2" << endl;
	}
	virtual ~A()
	{
		cout << "a的析构" << endl;
		func();
	}
};
class B:public A
{
public:
	B()
	{
		cout << "b的构造" << endl;
	}
	void func()		
	{
		cout << "b的func" << endl;
		func2();
	}
	void func2()
	{
		cout << "b的func2" << endl;
	}
	~B()
	{
		cout << "b的析构" << endl;
		func();
	}
};
int main(int argc, char* argv[])
{
	A *p = new B;
	cout << endl;
	p->func();
	cout << endl;
	delete p;
	return 0;
}

func为虚函数,p->func(),先调用B::func(),func2为虚函数,调用B::func2();
父类构造函数为虚,则delete p时,先调用子类析构:func为虚函数,先调用B::func(),func2为虚函数,调用B::func2()
再调用父类析构,func为虚函数,func2为虚函数,但子类已析构,调用A::func(),A::func2();
在这里插入图片描述
若将父类析构改为非虚,则输出为
在这里插入图片描述
此时子类析构函数没有执行,且父类析构中的虚函数都是其自身作用域下的函数。

若将func改为非虚,则输出为
在这里插入图片描述
可以看到,p->func执行的是父类的func,但其内的虚函数func2执行的仍是子类的func2。

### C++ 指针概念的大白话解释 #### 什么是指针? 指针是一个特殊的变量,它的值是另一个变量的地址。换句话说,指针存储的是内存位置而不是具体的数值[^1]。 例如,在C++中声明一个整数类型的指针: ```cpp int *ptr; ``` 这里的`*`表示这是一个指向整数类型数据的指针。如果有一个整数变量`num`: ```cpp int num = 10; ``` 那么可以通过取址运算符`&`获取这个变量的地址并赋给指针: ```cpp ptr = &num; ``` 此时`ptr`保存的就是`num`所在的内存地址。 #### 如何理解指针的作用? 想象一下图书馆里的书架编号系统。假设有一本书放在某个特定的位置上(比如第7排第3层),而你只需要记住这本书所在的具体坐标就能快速找到它。同样地,在计算机程序里,当创建了一个变量之后,操作系统会给其分配一段独一无二的记忆空间;如果我们想操作该变量的内容而不直接提及名称的话,则需要用到能够记录下这段记忆区域起始处的信息——这就是所谓的“指针”。 另外值得注意的一点是在定义多个同种类型的指针时,把星号紧挨着类型名可以帮助程序员更好地理解和维护代码逻辑[^2]: ```cpp // 这样写更清晰明了 int* p1, p2; // 只有p1是指向int的指针,p2不是 int *q1,*q2; // q1,q2都是指向int的指针 ``` #### 动态内存管理中的应用 除了作为普通变量地址外,指针还广泛应用于动态内存分配场景之中。例如使用`new`关键字可以在堆区申请一块新的未被使用的连续字节序列来构建对象实例,并返回这块新辟出来的首部位置供后续调用者存入实际的数据结构体成员或者数组元素等等[^3]。 ```cpp MyClass* obj = new MyClass(); delete obj; ``` 以上就是关于C++指针的一些基础介绍以及大白话理解方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值