调用多态Pokemon对象attacked函数遇编译错误:‘this’参数为const Pokemon
嘿,我来帮你拆解下这个编译错误的原因,其实问题出在你可能没注意到的lambda表达式细节上,还有一个明显的参数遗漏问题:
错误根源
Lambda的const特性导致的问题
你在QTimer::singleShot里用了[=]按值捕获变量,这会把sPokemon复制一份到lambda内部。默认情况下,lambda表达式的调用运算符operator()是const修饰的——这意味着lambda里的sPokemon副本是const Pokemon类型的。而你的attacked函数是非const成员函数,C++规定const对象不能调用非const成员函数,所以就出现了那个报错。attacked函数调用参数缺失
你的Pokemon::attacked函数定义是void attacked(int value),明确需要传入一个int类型的伤害值,但你调用的时候写的是sPokemon.attacked(),完全没有传参数,这其实也是一个编译错误,只是编译器优先报了const相关的问题而已。
修复方案
针对这两个问题,我们可以这样修改:
方案一:按引用捕获变量(推荐)
直接用[&]按引用捕获,这样lambda内部操作的是原sPokemon对象,不会产生const副本,同时补上attacked需要的参数(比如用对方的攻击值作为参数):
void FightWidget::fight(Pokemon &mPokemon, Pokemon &sPokemon) { bool flag = false; // 注意:这里的while循环会无限创建定时器,实际运行会导致程序资源耗尽,必须补充终止逻辑 while(flag == false) { QTimer::singleShot(200, this, [&]{ // 传入攻击值,比如调用mPokemon的attack函数获取伤害 sPokemon.attacked(mPokemon.attack()); // 补充终止循环的逻辑,比如判断双方HP是否归零 if (sPokemon.hp <= 0 || mPokemon.hp <= 0) { flag = true; } }); // 注意:这里需要添加延迟或者事件循环处理,否则while会瞬间创建无数定时器 // 比如可以用QEventLoop或者调整逻辑避免同步循环 } }
方案二:给lambda添加mutable关键字
如果你确实需要按值捕获,可以给lambda加上mutable关键字,这样lambda的operator()就会变成非const,内部的捕获变量也不再是const:
QTimer::singleShot(200, this, [=]() mutable { sPokemon.attacked(mPokemon.attack()); });
额外提醒
你的fight函数里的while(flag == false)是同步循环,而QTimer::singleShot是异步执行的,这个循环会瞬间创建大量定时器,导致程序卡死。你需要调整逻辑,比如用事件循环或者在lambda内部判断终止条件,避免无限创建定时器。
内容的提问来源于stack exchange,提问作者liushi

