C++非静态成员引用错误:GetName函数调用问题求助
嗨,这个问题的根源其实很清晰:你在静态成员函数里直接调用了非静态的GetName方法。静态函数属于整个类,不依附于任何具体的对象实例,所以它没法直接调用那些需要对象才能运行的非静态成员函数——编译器根本不知道该用哪个Exchanger_npc对象来执行GetName,自然就抛出这个错误了。
具体问题拆解
你的OnGossipHello和OnGossipSelect都是标记为static的函数,但GetName是Exchanger_npc类里的普通成员函数。当静态函数尝试调用GetName时,因为没有对应的对象实例,编译器就懵了,于是报错。
两种修复方案(推荐第一种)
方案1:把GetName改成静态成员函数
看GetName的实现,它只用到了全局的sObjectMgr,完全不需要访问Exchanger_npc类的任何实例成员,所以直接把它改成静态函数就搞定了:
static std::string GetName(uint32 entry) { // 建议加个空指针检查,避免无效物品ID导致崩溃 ItemTemplate const* itemTemp = sObjectMgr->GetItemTemplate(entry); return itemTemp ? itemTemp->Name1 : "Unknown Item"; };
这样静态的OnGossipHello和OnGossipSelect就能直接调用它,编译器也不会有意见了。
方案2:传入类实例调用(不推荐)
如果因为某些原因不能把GetName改成静态,那你得在调用时提供一个Exchanger_npc的对象实例。不过你的场景里OnGossipHello是静态的,没有现成的实例引用,这种方式会很麻烦,所以更推荐方案1。
修改后的完整代码(关键部分已修正)
我还顺便调整了MyAI的位置,把它放到了Exchanger_npc的私有域里,更符合类封装的规范,同时明确了静态函数的调用路径:
#include "ScriptMgr.h" #include "Creature.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "ObjectMgr.h" #include "Player.h" #include "WorldSession.h" struct tokenData { uint32 TAKE_ENTRY, TAKE_AMOUNT, GIVE_ENTRY, GIVE_AMOUNT; }; struct tokenData Tokens[] = { {191201, 10, 191202, 1}, {191202, 1, 191201, 10}, {191202, 25, 191203, 1}, {191203, 1, 191202, 25}, {191203, 50, 191204, 1}, {191204, 1, 191203, 50}, {191204, 100, 191205, 1}, {191205, 1, 191204, 100} }; const uint32 tokensSize = sizeof Tokens / sizeof(*Tokens); class Exchanger_npc : public CreatureScript { public: Exchanger_npc() : CreatureScript("Exchanger_npc") { } // 改成静态成员函数 static std::string GetName(uint32 entry) { // 建议加个空指针检查,避免无效物品ID导致崩溃 ItemTemplate const* itemTemp = sObjectMgr->GetItemTemplate(entry); return itemTemp ? itemTemp->Name1 : "Unknown Item"; }; static bool OnGossipHello(Player* player, Creature* creature) { for (uint32 i = 0; i < tokensSize; ++i) { std::ostringstream ss; ss << "Swap " << Tokens[i].TAKE_AMOUNT << " x " << GetName(Tokens[i].TAKE_ENTRY) << " to " << Tokens[i].GIVE_AMOUNT << " x " << GetName(Tokens[i].GIVE_ENTRY); AddGossipItemFor(player, 0, ss.str(), GOSSIP_SENDER_MAIN, i, "Are you sure?", 0, false); } SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); return true; } static bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { player->PlayerTalkClass->ClearMenus(); if (sender == GOSSIP_SENDER_MAIN && action < tokensSize) { if (player->HasItemCount(Tokens[action].TAKE_ENTRY, Tokens[action].TAKE_AMOUNT)) { if (player->AddItem(Tokens[action].GIVE_ENTRY, Tokens[action].GIVE_AMOUNT)) { player->DestroyItemCount(Tokens[action].TAKE_ENTRY, Tokens[action].TAKE_AMOUNT, true); player->GetSession()->SendAreaTriggerMessage("%u x %s swapped to %u x %s", Tokens[action].TAKE_AMOUNT, GetName(Tokens[action].TAKE_ENTRY).c_str(), Tokens[action].GIVE_AMOUNT, GetName(Tokens[action].GIVE_ENTRY).c_str()); } } else player->GetSession()->SendNotification("You need at least %u x %s", Tokens[action].TAKE_AMOUNT, GetName(Tokens[action].TAKE_ENTRY).c_str()); } OnGossipHello(player, creature); return true; } CreatureAI* GetAI(Creature* creature) const override { return new MyAI(creature); } private: struct MyAI : public ScriptedAI { MyAI(Creature* creature) : ScriptedAI(creature) { } bool GossipHello(Player* player) override { return Exchanger_npc::OnGossipHello(player, me); } bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override { uint32 sender = player->PlayerTalkClass->GetGossipOptionSender(gossipListId); uint32 action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId); return Exchanger_npc::OnGossipSelect(player, me, sender, action); } }; }; void AddSC_Exchanger_npc() { new Exchanger_npc(); }
额外小提示
我在GetName里加了一个空指针检查,避免传入无效的物品ID时触发空指针崩溃——如果sObjectMgr->GetItemTemplate返回nullptr,就返回"Unknown Item",这样程序会更健壮。
内容的提问来源于stack exchange,提问作者user5749981

