C++编程:虚拟析构函数、多重继承与链表的深入解析
立即解锁
发布时间: 2025-08-20 01:48:57 阅读量: 1 订阅数: 3 


懒惰程序员的C++入门指南
### C++ 编程:虚拟析构函数、多重继承与链表的深入解析
#### 1. 虚拟析构函数
在 C++ 编程中,当使用动态内存分配时,我们需要在使用完后释放这些内存。以 `Text` 类为例,其代码如下:
```cpp
//Text class, for use with the SSDL library
#ifndef TEXT_H
#define TEXT_H
#include "shape.h"
class Text: public Shape
{
public:
Text (const char* txt = "") { copy (txt); }
Text (const Text& other) : Shape (other)
{
copy (other.contents_);
}
Text (int x, int y, const char* txt = "") : Shape(x, y)
{
copy(txt);
}
~Text () override { if (contents_) delete contents_; }
const Text& operator=(const Text& other);
const char* contents () const { return contents_; }
void drawAux () const override
{
SSDL_RenderText (contents_, location().x_, location().y_);
}
private:
char* contents_;
void copy (const char* txt);//used for copying contents
};
#endif
```
`Text` 类使用动态内存分配字符数组,使用完后需要释放。但在 `main` 函数中:
```cpp
for (int i = 0; i < olympicSymbol.size(); ++i)
delete olympicSymbol [i];
```
由于 `olympicSymbol [i]` 是指向 `Shape` 的指针,而非 `Text`,所以只会删除 `Shape` 相关的内容,无法释放 `Text` 的 `contents_`。
解决方法是将 `Shape` 的析构函数设为虚拟函数,`Text` 的析构函数进行重写:
```cpp
virtual Shape::~Shape () { if (description_) delete[] description_; }
Text::~Text () override { if (contents_) delete contents_; }
```
这样,当调用 `Shape` 的析构函数时,会根据实际对象类型调用正确的析构函数。
虚拟函数的黄金法则:
- 通常版本:如果在类层次结构中使用虚拟函数,应将析构函数设为虚拟函数。
- 更强版本:由于编写类时无法预知子类的使用情况,应将所有析构函数设为虚拟函数。
即使使用 C++ 的 `string` 类,同样需要为 `Shape` 提供虚拟析构函数:
```cpp
virtual Shape::~Shape () { }
```
#### 2. 继承与移动构造函数/移动赋值运算符
在为 `Shape` 及其子类编写移动构造函数和移动赋值运算符时,可能会遇到问题。例如,在 `Circle` 类中:
```cpp
Circle (Circle&& c) : Shape (c) //Nope, not working right...
{
radius_ = c.radius();
}
```
这里会调用 `Shape` 的普通复制构造函数。因为在构造函数中,`c` 的右值属性被移除。
解决方法是使用 `std::move` 将其强制转换为右值:
```cpp
#include <utility> //for std::move
...
Circle (Circle&& c) : Shape (std::move (c))
{
radius_ = c.radius();
}
```
移动赋值运算符同理:
```cpp
const Circle& operator= (Circle&& c)
{
Shape::operator=(std::move(c)); radius_ = c.radius();
return *this;
}
```
#### 3. 调试建议
在编程过程中,可能会遇到以下问题:
- 编译器提示子类的重写函数与基类不匹配,可能是函数头遗漏 `const`、函数名拼写错误或参数列表不同。
- 编译器提示子类是抽象类,但子类中没有纯虚函数。可能是忘记重写父类的纯虚函数,或者忘记将子类函数标记为 `override`。解决方法是添加 `override`。
#### 4. 练习
- **射击游戏**:在简单射击游戏中,`Powerup` 是可被鼠标点击的目标。需修改 `main.cpp` 使用指针,并在 `Powerup` 类层次结构中正确添加 `virtual` 和 `override`。建议将 `Powerup` 设为抽象类。
- **卡片组**:在 `CardGroup` 类层次结构中,为可能需要的子类添加 `isLegalToAdd` 和 `isLegalToRemove` 函数。让 `CardGroup` 的 `addCardLegally` 调用 `isLegalToAdd`,使用虚拟函数确保调用正确的子类版本。
- **非图形化 FreeCell 游戏*
0
0
复制全文
相关推荐








