题目
设有下面的类定义:
class A{
public:
virtual void p(){print("A")}
virtual ~A(){ }
};
class B:public A{
public:
void p(){print("B")}
~B(){ }
};
请简要说明关键字 virtual
是什么含义?在什么情况下,会在类 A 的析构函数~A()
前面加 virtual
关键词?
virtual
关键字的含义
定义:
virtual
关键字用于C++中类的成员函数声明中,表示该成员函数是虚函数(virtual function)。虚函数允许在派生类中重写,并支持运行时多态性(dynamic polymorphism)。
主要作用:
- 多态性: 使得基类指针或引用能够调用派生类中重写的函数实现。
- 动态绑定: 在运行时决定调用哪个版本的函数(基类的还是派生类的),而不是在编译时。
示例解释
在题目提供的类定义中:
class A {
public:
virtual void p() { print("A"); }
virtual ~A() { }
};
class B : public A {
public:
void p() { print("B"); }
~B() { }
};
A
类中的p
函数被声明为虚函数,这意味着它可以在派生类B
中被重写。- 当使用
A
类的指针或引用指向B
类的对象时,调用p
函数将执行B
类中的实现,而不是A
类中的实现。这种行为是多态性的体现。
析构函数前加 virtual
的情况
在类 A
的析构函数 ~A()
前面加 virtual
关键字的原因是为了确保当通过基类指针或引用删除派生类对象时,派生类的析构函数能够正确调用。
具体场景:
-
基类指针指向派生类对象:
当使用基类指针指向派生类对象并且需要删除对象时,若基类的析构函数是虚函数,那么派生类的析构函数也会被正确调用,确保派生类和基类的资源都能被正确释放。 -
防止内存泄漏:
如果基类的析构函数不是虚函数,通过基类指针删除派生类对象时,只会调用基类的析构函数,派生类的析构函数不会被调用,可能导致派生类的资源没有被正确释放,进而引发内存泄漏。
代码示例
假设存在以下代码段:
A* obj = new B();
delete obj;
在这种情况下,如果类 A
的析构函数是虚函数:
- 类
A
的析构函数为虚函数: 删除对象时,首先调用B
类的析构函数,然后调用A
类的析构函数,确保派生类和基类的资源都被正确释放。
class A {
public:
virtual ~A() { std::cout << "A's destructor called" << std::endl; }
};
class B : public A {
public:
~B() { std::cout << "B's destructor called" << std::endl; }
};
- 类
A
的析构函数不是虚函数: 删除对象时,只会调用A
类的析构函数,B
类的析构函数不会被调用,可能导致资源泄漏。
总结
virtual
关键字: 用于声明虚函数,支持运行时多态性,使得基类指针或引用可以调用派生类的重写函数。- 析构函数前加
virtual
: 当基类指针或引用指向派生类对象并需要删除对象时,确保派生类和基类的析构函数都能正确调用,防止内存泄漏。