我正在尝试为一个基于文本的游戏实现一个角色选择方法,我知道它不会像我做的那样工作,因为我正在返回一个对象的引用,该对象的生存期限制在方法调用的范围内。 我还尝试过在不引用Fighter父类和基于玩家角色选择返回子类(Samus和Ryu)的情况下实现该方法,但我会得到这样的错误:无效的抽象返回类型'Fighter‘。
Fighter characterSelection(int player,bool checkForBot, Fighter &fig)
{
int input;
string newName;
if(checkForBot)
{
input = (rand()%2)+1;
}
else{
cout << "Please choose your Fighter player"<<player<<": \n1. Samus\n2. Ryu\n";
input = readInput<int>();
}
if(input == 1)
{
Samus sam;
if(checkForBot)
{
cout << "Bot selected Samus!";
}
else{
cout << "Player"<<player<<" selected Samus!\nDo you wish to change your fighters name?\n1.Yes\n2.No\n";
input = readInput<int>();
if(input == 1)
{
cout << "new Name: ";
newName = readInput<string>();
changeName(newName,sam);
}
}
return sam;
}
else if(input == 2)
{
Ryu ry;
if(checkForBot)
{
cout << "Bot selected Ryu!";
}
else {
cout << "Player"<<player<<" selected Ryu!\nDo you wish to change your fighters name?\n1.Yes\n2.No\n";
input = readInput<int>();
if(input == 1)
{
cout << "new Name: ";
newName = readInput<string>();
changeName(newName,ry);
}
}
return ry;
}
}
在选择了一个字符和函数调用结束后,调用对象的析构函数,从而使引用链接到一个不存在的对象。
int main()
{
int input;
string newName;
bool checkForBot;
int player=1;
while(true)
{
cout << "1. PVP \n2. PVE\n";
input = readInput<int>();
if(input == 1)
{
checkForBot = false;
//Character Selection
Fighter &fig1 = characterSelection(player,checkForBot,fig1);
player++;
Fighter &fig2 = characterSelection(player,checkForBot,fig2);
//Battle
fightPVP(fig1, fig2);
}
else if(input ==2)
{
//Character Selection
Fighter &fig1 = characterSelection(player,checkForBot,fig1);
checkForBot = true;
Fighter &bot = characterSelection(player,checkForBot,bot);
//Battle
fightPVE(fig1, bot);
}
}
return 0;
}
有没有其他方法可以解决这个问题,而不是引用父类,然后在函数调用中创建子类?
在此:
Fighter &fig1 = characterSelection(player,checkForBot,fig1);
您正在对函数返回的本地对象副本进行引用。
返回父对象也有对象切片的问题; 你应该把它记在帐上。
但是,如果这不是问题,您可以向类添加一个复制构造函数,并在声明接收变量时删除引用:
Fighter fig1 = characterSelection(player,checkForBot,fig1);
如果对象不适合复制,另一种方法是在CharacterSelection
中New
对象,并返回基类的指针(更好,共享指针)。
在您的代码的情况下,编译器是正确的。 从函数'characterselection'中返回抽象类斗士的一个实例,这是错误的,因为抽象类不能实例化。 只能返回指针或引用(fighter*或figther&;) 指向抽象类(指针通常是首选方式)。 根据我的知识,在运行时使用抽象类的继承和一种斗士的选择来实现您想要的目标的唯一方法是:
#include <iostream>
class Fighter
{
public:
virtual void f() = 0;
virtual ~Fighter() {};
};
class Samus : public Fighter
{
public:
void f() { std:: cout << "Samus\n"; }
};
class Ryu : public Fighter
{
public:
void f() { std:: cout << "Ryu\n"; }
};
Fighter* getFigther()
{
int fighterCode;
std::cin >> fighterCode;
switch (fighterCode)
{
case 0: return new Samus();
case 1: return new Ryu();
default: return nullptr;
}
}
int main()
{
Fighter* myF = getFigther();
// Do what you want with the fighter
myF->f();
// Release the resources
delete myF;
}
如果您想要避免基于任何原因的堆分配,可以通过使用placement new语法来实现:
#include <iostream>
class Fighter
{
public:
virtual void f() = 0;
virtual ~Fighter() {};
};
class Samus : public Fighter
{
public:
void f() { std:: cout << "Samus\n"; }
};
class Ryu : public Fighter
{
public:
void f() { std:: cout << "Ryu\n"; }
};
constexpr std::size_t size()
{
constexpr std::size_t samusS = sizeof(Samus);
constexpr std::size_t ryuS = sizeof(Ryu);
return samusS < ryuS ? ryuS : samusS;
}
void getFigther(Fighter*& f)
{
int fighterCode;
std::cin >> fighterCode;
// If figtherCode is invaild you can print a message or throw an exception
switch (fighterCode)
{
case 0: new (f) Samus(); break;
case 1: new (f) Ryu(); break;
}
}
int main()
{
char space[size()];
Fighter* myF = (Fighter*) (space);
getFigther(myF);
// Do what you want with the fighter
// No delete requied
myF->f();
}
但是,如果您有多个不同大小的战斗机类,您将需要一个编译时函数来为您提供任何类(代表战斗机)的最大大小。 我认为在你的情况下这种方法不值得努力。