模板泛化类如何卸载释放内存
CustomWidget::~CustomWidget() {
for (size_t i = 0; i < buttonManager.registerItem.size(); ++i) {
delete buttonManager.registerItem(exitButton);
}
}
以上该怎么写删除对象操作,类如下:
template <typename T>
class GenericManager {
public:
using ConditionFunc = std::function<bool(const T&, const QPoint&)>;
using ActionFunc = std::function<void(QPainter&, const T&, bool)>;
GenericManager() {}
void registerItem(T* item) {
int count = items.count();
qWarning("Inserting at index %d, current count: %d", count, count);
items.insert(count, item);
}
void processItems(QPainter& bufferPainter, QMouseEvent* event, QWidget* widget,
ConditionFunc conditionFunc, ActionFunc actionFunc) {
QPoint cursorPos = event ? event->pos() : widget->mapFromGlobal(QCursor::pos());
// 将 i 的类型改为 size_t
for (size_t i = 0; i < items.count(); ++i) {
T* item = items.at(i);
if (item) {
qWarning("Inserting at index");
bool shouldHighlight = conditionFunc(*item, cursorPos);
actionFunc(bufferPainter, *item, shouldHighlight);
}
}
}
private:
QPtrVector<T> items;
};
使用模板来泛化类,如何增加删除对象的处理,增加代码如下:
// 提供一个公共方法来获取 items 的数量
size_t getItemCount() const {
return items.count();
}
// 提供一个公共方法来获取指定索引的元素
T* getItemAt(size_t index) const {
if (index < items.count()) {
return items.at(index);
}
return nullptr;
}
析构函数删除对象:
CustomWidget::~CustomWidget() {
// 遍历 GenericManager 中的 items 并释放内存
for (size_t i = 0; i < buttonManager.getItemCount(); ++i) {
ButtonInfo* item = buttonManager.getItemAt(i);
if (item) {
delete item;
}
}
}
注意不能用T* item= buttonManager.getItemAt(i);这样, CustomWidget
的析构函数中正确释放内存
T
是未定义的标识符,因为 T
是 GenericManager
类模板的模板参数,在 CustomWidget
类的作用域内并没有这个类型定义。而在 CustomWidget
里使用的是 GenericManager<ButtonInfo>
,所以应该明确使用 ButtonInfo*
来接收 getItemAt
方法返回的指针。
调用方式:
void CustomWidget::paintEvent(QPaintEvent *event) {
bufferPixmap = QPixmap(size());
//bufferPixmap.fill(Qt::transparent);
QPainter bufferPainter(&bufferPixmap);
// drawBackgroundAndBorder(bufferPainter);
buttonManager.processItems(bufferPainter, nullptr, this,
[](const ButtonInfo& button, const QPoint& cursorPos) {
return button.rect.contains(cursorPos);
},
[this](QPainter& painter, const ButtonInfo& button, bool isHighlighted) { // 添加 this 到捕获列表
QRect drawRect(button.rect.x(), button.rect.y(), button.rect.width(), button.rect.height());
qWarning("Draw rect: (%d, %d, %d, %d)", drawRect.x(), drawRect.y(), drawRect.width(), drawRect.height());
QImage img;
img.loadFromData(isHighlighted ? button.highlight_png : button.normal_png,
isHighlighted ? button.highlight_png_size : button.normal_png_size,
"PNG");
if (img.isNull()) {
// 使用 qWarning 替代 qDebug
qWarning("Failed to load image");
}
// 如果 Qt 版本支持,可以保留下面这行
// painter.setRenderHint(QPainter::Antialiasing);
this->simulateLinearGradient(painter, drawRect, QColor(15, 10, 60), QColor(7, 69, 111));
painter.drawImage(drawRect, img);
}
);
QPainter painter(this);
painter.drawPixmap(0, 0, bufferPixmap);
}
注意,可以随意设置条件和绘制内容,conditionFun本例是lambda表达式 return button.rect.contains(cursorPos);
绘制结果简单一句img.loadFromData(isHighlighted ? button.highlight_png : button.normal_png,
isHighlighted ? button.highlight_png_size : button.normal_png_size,
"PNG");
这样充分利用C++的新特性,代码变得简单清晰
在 C++ 的 Lambda 表达式中,方括号 []
部分被称为捕获列表,它用于指定 Lambda 表达式可以访问哪些外部变量。捕获列表不同的写法有不同的作用,下面详细解释为什么在你的代码里一个 Lambda 用 []
,另一个用 [this]
。
1. []
捕获列表
[](const ButtonInfo& button, const QPoint& cursorPos) {
return button.rect.contains(cursorPos);
}
这里使用 []
表示该 Lambda 表达式不捕获任何外部变量。这个 Lambda 表达式作为 conditionFunc
传递给 buttonManager.processItems
方法,它只依赖于传入的参数 button
和 cursorPos
,不需要访问外部作用域中的任何变量,所以捕获列表为空。它的功能仅仅是判断鼠标位置 cursorPos
是否在按钮的矩形区域 button.rect
内。
2. [this]
捕获列表
[this](QPainter& painter, const ButtonInfo& button, bool isHighlighted) {
QRect drawRect(button.rect.x(), button.rect.y(), button.rect.width(), button.rect.height());
qWarning("Draw rect: (%d, %d, %d, %d)", drawRect.x(), drawRect.y(), drawRect.width(), drawRect.height());
QImage img;
img.loadFromData(isHighlighted ? button.highlight_png : button.normal_png,
isHighlighted ? button.highlight_png_size : button.normal_png_size,
"PNG");
if (img.isNull()) {
qWarning("Failed to load image");
}
this->simulateLinearGradient(painter, drawRect, QColor(15, 10, 60), QColor(7, 69, 111));
painter.drawImage(drawRect, img);
}
这里使用 [this]
表示该 Lambda 表达式捕获当前对象的指针 this
。在这个 Lambda 表达式中,调用了 this->simulateLinearGradient
方法,这是当前对象 CustomWidget
的一个成员函数。为了能够访问当前对象的成员函数和成员变量,需要通过 this
指针,所以在捕获列表中指定 this
。这样,Lambda 表达式就可以在其内部调用当前对象的方法和访问成员变量了。
总结
[]
:不捕获任何外部变量,Lambda 表达式只能使用其参数列表中的变量。[this]
:捕获当前对象的指针,Lambda 表达式可以访问当前对象的成员函数和成员变量。
通过合理使用捕获列表,可以让 Lambda 表达式根据需要访问外部作用域中的变量,从而实现更灵活的功能