引发异常:读取访问冲突。 std :: shared_ptr <Weapon> :: operator -> <Weapon, 0> (...) returned nullptr., happened
Exception raised: read access violation. std :: shared_ptr <Weapon> :: operator -> <Weapon, 0> (...) returned nullptr., happened
问题
程序启动和调试过程中出现异常。使用 get ????? 获取数据时出现异常() 方法;武器class。异常看起来像这样:
出现异常:侵犯阅读权限。 std :: shared_ptr :: operator -> (...) 返回 nullptr。 Hero.h中的代码注释掉了问题片段,方法调用。
Main.cpp
#include "Hero.h"
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <time.h>
Hero* GetSomeHero()
{
switch (1 + rand() % 5)
{
case 1: return new Human(100);
case 2: return new King(300);
case 3: return new Queen(150);
case 4: return new Knight(200);
case 5: return new Troll(250);
}
return new Human(100);
}
int main()
{
srand((unsigned int)time(0));
std::shared_ptr<Hero> hero(GetSomeHero());
std::shared_ptr<Hero> enemy(GetSomeHero());
while (true)
{
hero->attackOutput(*enemy);
enemy->attackOutput(*hero);
if (hero->isDead())
{
std::shared_ptr<Hero> temp(GetSomeHero());
hero.swap(temp);
}
if (enemy->isDead())
{
std::shared_ptr<Hero> temp(GetSomeHero());
enemy.swap(temp);
}
std::cout << *hero << std::endl << *enemy << std::endl;
Sleep(200);
system("cls");
}
system("pause");
return 0;
}
Weapon.h
#pragma once
#include <string>
class Weapon
{
protected:
std::string name;
float damage;
int wear;
public:
Weapon(std::string name, float damage, int wear)
{
this->name = name;
this->damage = damage;
this->wear = wear;
}
virtual void setWear(int wear) = 0;
virtual std::string getName() = 0;
virtual float getDamage() = 0;
virtual int getWear() = 0;
};
class Fist : public Weapon // KULAK
{
protected:
public:
Fist() : Weapon("Fist", 1, 3) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Knife : public Weapon // NOZH
{
protected:
public:
Knife() : Weapon("Knife", 5, 5) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Bow : public Weapon // LUCK
{
protected:
public:
Bow() : Weapon("Bow", 15, 10) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Ax : public Weapon // TOPOR
{
protected:
public:
Ax() : Weapon("Ax", 30, 5) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Sword : public Weapon // MECH
{
protected:
public:
Sword() : Weapon("Sword", 25, 8) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
Hero.h
#include "Weapon.h"
#include <iostream>
#include <string>
#include <cstdlib>
class Hero
{
protected:
std::shared_ptr<Weapon> weapon;
std::string name;
float health;
int pressure;
int beauty;
int skill;
int horror;
public:
Hero(std::string name, float health, int pressure, int beauty, int skill, int horror)
{
this->name = name;
this->health = health;
this->pressure = 1 + rand() % pressure;;
this->beauty = 1 + rand() % beauty;
this->skill = 1 + rand() % skill;
this->horror = 1 + rand() % horror;
}
friend std::ostream& operator<<(std::ostream& os, const Hero& obj)
{
os << std::endl
<< obj.name << std::endl
<< "Health: " << obj.health << std::endl
/*<< "Weapon: " << obj.weapon->getName() << "[" << obj.weapon->getDamage() << "]\n"*/
<< "Specifications:\n"
<< "Pressure[" << obj.pressure << "], Beauty[" << obj.beauty << "], Skill[" << obj.skill << "], Horror[" << obj.pressure << "]\n";
return os;
}
bool isDead()
{
if (this->health > 0) return false;
else return true;
}
virtual void weaponСhange() = 0;
virtual void attackOutput(Hero& enemy) = 0;
virtual void attackInput(int damage) = 0;
};
class Human : public Hero
{
protected:
public:
Human(float health) : Hero("Human", health, 1, 1, 1, 1) {}
virtual void weaponСhange()
{
weapon = std::shared_ptr<Weapon>(new Fist);
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class King : public Hero
{
protected:
public:
King(float health) : Hero("King", health, 10, 15, 4, 3) {}
virtual void weaponСhange()
{
switch (1 + rand() % 3)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Knife);
case 3: weapon = std::shared_ptr<Weapon>(new Ax);
case 4: weapon = std::shared_ptr<Weapon>(new Sword);
}
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 + this->pressure + this->skill /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Queen : public Hero
{
protected:
public:
Queen(float health) : Hero("Queen", health, 2, 15, 10, 1) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 2)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Knife);
case 3: weapon = std::shared_ptr<Weapon>(new Bow);
}
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 + this->beauty + this->skill /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Knight : public Hero
{
protected:
public:
Knight(float health) : Hero("Knight", health, 15, 6, 20, 1) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 2)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Ax);
case 3: weapon = std::shared_ptr<Weapon>(new Sword);
}
}
virtual void attackOutput(Hero& enemy)
{
if (weapon->getWear() <= 0) this->weaponСhange();
enemy.attackInput(1 + this->skill + this->pressure /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Troll : public Hero
{
protected:
public:
Troll(float health) : Hero("Troll", health, 20, 1, 1, 10) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 1)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Ax);
}
}
virtual void attackOutput(Hero& enemy)
{
if (weapon->getWear() <= 0) this->weaponСhange();
enemy.attackInput(1 + this->horror + this->pressure /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
导致崩溃的问题很可能是您在 attackOutput()
中为 Knight
和 Troll
调用了 weapon->getWear()
。你在为他们分配武器之前执行此操作。
另一个问题:您还没有将基 class 设为析构函数 virtual
。这意味着智能指针只会在销毁对象时销毁对象的基 class 部分。
第三个问题:你的很多switch
都会给变量赋值,但不会break
所以值会被一遍又一遍的覆盖,最后会被赋值为上次的值case
。在这种情况下,您将获得一个随机数 [1, 3]
(而不是 [1, 4]
),并且每次都会获得一个 Sword
。
switch (1 + rand() % 3)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist); // missing break;
case 2: weapon = std::shared_ptr<Weapon>(new Knife); // missing break;
case 3: weapon = std::shared_ptr<Weapon>(new Ax); // missing break;
case 4: weapon = std::shared_ptr<Weapon>(new Sword); // missing break;
}
旁注:
首选weapon = std::make_shared<Fist>();
等而不是上面的
首选 std::unique_ptr
而不是 std::shared_ptr
除非你真的需要引用计数指针。
为伤害和健康等选择一种类型。您现在混合使用 float
和 int
。
当你重写子class中的成员函数时,你可以跳过virtual
说明符(没关系),而是添加override
说明符。如果该函数实际上没有覆盖虚函数,这将使编译器报错。
在逻辑表达式中为
bool isDead() {
if (this->health > 0) return false;
else return true;
}
您在 if(...)
中已经有一个布尔结果,所以更喜欢直接 return 它。在这种情况下,您可以简单地改为这样做:
bool isDead() {
return this->health <= 0;
}
使用 <random>
随机数生成器和支持函数以获得更好的随机化。由于您在 1
和某个最大值(含)之间生成了很多数字,因此您可以为它创建一个支持函数。示例:
#include <random>
int my_rand(int max) {
// the generator will only be seeded once since it's static
static std::mt19937 generator(std::random_device{}());
std::uniform_int_distribution<int> dist(1, max); // range: [1, max]
return dist(generator);
}
如果您有一些虚函数的默认实现,您可以在基础 class 中实现它以节省很多 copy/pasting。只有在你想要一些特别的东西的情况下才覆盖它。一些 Weapon
s 的示例:
class Weapon {
private:
// Direct access to member variables is usually not a good idea. Try to keep them
// private.
std::string name;
float damage;
int wear;
protected:
// The constructor can be protected, only subclasses will be able to use it.
Weapon(std::string Name, float Damage, int Wear) : // use the initializer list
name(Name), damage(Damage), wear(Wear)
{}
// virtual destructor
virtual ~Weapon() = default;
public:
virtual void setWear(int Wear) { wear = Wear; }
virtual void applyWear() { --wear; }
virtual const std::string& getName() { return name; }
virtual float getDamage() const { return damage; }
virtual int getWear() { return wear; }
};
class Fist : public Weapon // KULAK
{
public:
Fist() : Weapon("Fist", 1, 3) {}
};
class Knife : public Weapon // NOZH
{
public:
Knife() : Weapon("Knife", 5, 5) {}
};
...
问题
程序启动和调试过程中出现异常。使用 get ????? 获取数据时出现异常() 方法;武器class。异常看起来像这样: 出现异常:侵犯阅读权限。 std :: shared_ptr :: operator -> (...) 返回 nullptr。 Hero.h中的代码注释掉了问题片段,方法调用。
Main.cpp
#include "Hero.h"
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <time.h>
Hero* GetSomeHero()
{
switch (1 + rand() % 5)
{
case 1: return new Human(100);
case 2: return new King(300);
case 3: return new Queen(150);
case 4: return new Knight(200);
case 5: return new Troll(250);
}
return new Human(100);
}
int main()
{
srand((unsigned int)time(0));
std::shared_ptr<Hero> hero(GetSomeHero());
std::shared_ptr<Hero> enemy(GetSomeHero());
while (true)
{
hero->attackOutput(*enemy);
enemy->attackOutput(*hero);
if (hero->isDead())
{
std::shared_ptr<Hero> temp(GetSomeHero());
hero.swap(temp);
}
if (enemy->isDead())
{
std::shared_ptr<Hero> temp(GetSomeHero());
enemy.swap(temp);
}
std::cout << *hero << std::endl << *enemy << std::endl;
Sleep(200);
system("cls");
}
system("pause");
return 0;
}
Weapon.h
#pragma once
#include <string>
class Weapon
{
protected:
std::string name;
float damage;
int wear;
public:
Weapon(std::string name, float damage, int wear)
{
this->name = name;
this->damage = damage;
this->wear = wear;
}
virtual void setWear(int wear) = 0;
virtual std::string getName() = 0;
virtual float getDamage() = 0;
virtual int getWear() = 0;
};
class Fist : public Weapon // KULAK
{
protected:
public:
Fist() : Weapon("Fist", 1, 3) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Knife : public Weapon // NOZH
{
protected:
public:
Knife() : Weapon("Knife", 5, 5) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Bow : public Weapon // LUCK
{
protected:
public:
Bow() : Weapon("Bow", 15, 10) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Ax : public Weapon // TOPOR
{
protected:
public:
Ax() : Weapon("Ax", 30, 5) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Sword : public Weapon // MECH
{
protected:
public:
Sword() : Weapon("Sword", 25, 8) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
Hero.h
#include "Weapon.h"
#include <iostream>
#include <string>
#include <cstdlib>
class Hero
{
protected:
std::shared_ptr<Weapon> weapon;
std::string name;
float health;
int pressure;
int beauty;
int skill;
int horror;
public:
Hero(std::string name, float health, int pressure, int beauty, int skill, int horror)
{
this->name = name;
this->health = health;
this->pressure = 1 + rand() % pressure;;
this->beauty = 1 + rand() % beauty;
this->skill = 1 + rand() % skill;
this->horror = 1 + rand() % horror;
}
friend std::ostream& operator<<(std::ostream& os, const Hero& obj)
{
os << std::endl
<< obj.name << std::endl
<< "Health: " << obj.health << std::endl
/*<< "Weapon: " << obj.weapon->getName() << "[" << obj.weapon->getDamage() << "]\n"*/
<< "Specifications:\n"
<< "Pressure[" << obj.pressure << "], Beauty[" << obj.beauty << "], Skill[" << obj.skill << "], Horror[" << obj.pressure << "]\n";
return os;
}
bool isDead()
{
if (this->health > 0) return false;
else return true;
}
virtual void weaponСhange() = 0;
virtual void attackOutput(Hero& enemy) = 0;
virtual void attackInput(int damage) = 0;
};
class Human : public Hero
{
protected:
public:
Human(float health) : Hero("Human", health, 1, 1, 1, 1) {}
virtual void weaponСhange()
{
weapon = std::shared_ptr<Weapon>(new Fist);
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class King : public Hero
{
protected:
public:
King(float health) : Hero("King", health, 10, 15, 4, 3) {}
virtual void weaponСhange()
{
switch (1 + rand() % 3)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Knife);
case 3: weapon = std::shared_ptr<Weapon>(new Ax);
case 4: weapon = std::shared_ptr<Weapon>(new Sword);
}
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 + this->pressure + this->skill /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Queen : public Hero
{
protected:
public:
Queen(float health) : Hero("Queen", health, 2, 15, 10, 1) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 2)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Knife);
case 3: weapon = std::shared_ptr<Weapon>(new Bow);
}
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 + this->beauty + this->skill /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Knight : public Hero
{
protected:
public:
Knight(float health) : Hero("Knight", health, 15, 6, 20, 1) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 2)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Ax);
case 3: weapon = std::shared_ptr<Weapon>(new Sword);
}
}
virtual void attackOutput(Hero& enemy)
{
if (weapon->getWear() <= 0) this->weaponСhange();
enemy.attackInput(1 + this->skill + this->pressure /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Troll : public Hero
{
protected:
public:
Troll(float health) : Hero("Troll", health, 20, 1, 1, 10) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 1)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Ax);
}
}
virtual void attackOutput(Hero& enemy)
{
if (weapon->getWear() <= 0) this->weaponСhange();
enemy.attackInput(1 + this->horror + this->pressure /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
导致崩溃的问题很可能是您在 attackOutput()
中为 Knight
和 Troll
调用了 weapon->getWear()
。你在为他们分配武器之前执行此操作。
另一个问题:您还没有将基 class 设为析构函数 virtual
。这意味着智能指针只会在销毁对象时销毁对象的基 class 部分。
第三个问题:你的很多switch
都会给变量赋值,但不会break
所以值会被一遍又一遍的覆盖,最后会被赋值为上次的值case
。在这种情况下,您将获得一个随机数 [1, 3]
(而不是 [1, 4]
),并且每次都会获得一个 Sword
。
switch (1 + rand() % 3)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist); // missing break;
case 2: weapon = std::shared_ptr<Weapon>(new Knife); // missing break;
case 3: weapon = std::shared_ptr<Weapon>(new Ax); // missing break;
case 4: weapon = std::shared_ptr<Weapon>(new Sword); // missing break;
}
旁注:
首选
weapon = std::make_shared<Fist>();
等而不是上面的首选
std::unique_ptr
而不是std::shared_ptr
除非你真的需要引用计数指针。为伤害和健康等选择一种类型。您现在混合使用
float
和int
。当你重写子class中的成员函数时,你可以跳过
virtual
说明符(没关系),而是添加override
说明符。如果该函数实际上没有覆盖虚函数,这将使编译器报错。在逻辑表达式中为
bool isDead() { if (this->health > 0) return false; else return true; }
您在
if(...)
中已经有一个布尔结果,所以更喜欢直接 return 它。在这种情况下,您可以简单地改为这样做:bool isDead() { return this->health <= 0; }
使用
<random>
随机数生成器和支持函数以获得更好的随机化。由于您在1
和某个最大值(含)之间生成了很多数字,因此您可以为它创建一个支持函数。示例:#include <random> int my_rand(int max) { // the generator will only be seeded once since it's static static std::mt19937 generator(std::random_device{}()); std::uniform_int_distribution<int> dist(1, max); // range: [1, max] return dist(generator); }
如果您有一些虚函数的默认实现,您可以在基础 class 中实现它以节省很多 copy/pasting。只有在你想要一些特别的东西的情况下才覆盖它。一些
Weapon
s 的示例:class Weapon { private: // Direct access to member variables is usually not a good idea. Try to keep them // private. std::string name; float damage; int wear; protected: // The constructor can be protected, only subclasses will be able to use it. Weapon(std::string Name, float Damage, int Wear) : // use the initializer list name(Name), damage(Damage), wear(Wear) {} // virtual destructor virtual ~Weapon() = default; public: virtual void setWear(int Wear) { wear = Wear; } virtual void applyWear() { --wear; } virtual const std::string& getName() { return name; } virtual float getDamage() const { return damage; } virtual int getWear() { return wear; } }; class Fist : public Weapon // KULAK { public: Fist() : Weapon("Fist", 1, 3) {} }; class Knife : public Weapon // NOZH { public: Knife() : Weapon("Knife", 5, 5) {} }; ...