如何在C++中将类的实例完全重新分配给同一类的另一个实例(然后删除原始对象)?



我正在通过制作主机游戏来弄乱C++。我有一个名为"武器类型"的超类。在此类中有一个静态方法,可以创建我需要的所有类型的武器。子类"武器"将从武器类型继承。(我是继承新手,所以请提前原谅我的无知。

我现在看到代码的方式是,每次创建 Weapon 子类的实例时,我都必须声明 WeaponType 超类的新实例。这是一个问题,因为我不想再创建 WeaponType 超类的任何实例,这些实例都在创建它们的静态方法中的堆上初始化。

我正在寻找一种方法来删除 WeaponType 超类的每个新实例,然后再对对象执行我需要的操作。(例如,如果创建另一个指定它应该是"近战"对象的 WeaponType 实例,并且我已经创建了一个名为"近战"的实例,我希望能够将 WeaponType "迁移"到原始对象并删除新对象(。

我拥有的代码不完整,但您应该能够了解我想要什么。

以下是 WeaponType 的大部分代码:

<!-- WeaponType.h -->
#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<map>
class WeaponType
{
private:
static std::map<int, WeaponType*> weapTypeAddresses;
/* Private setters */
static void setWeapTypeAddresses(const std::vector<WeaponType*>&);
protected:
double reloadSpeed;
int weapTypeID, ammoPerShot, maxAmmo;
std::string weapTypeName;
public:
/* Constructors */
WeaponType(int, double, int, int);
WeaponType(int);
WeaponType();
static void MakeWeaponTypes();
/* Destructor */
~WeaponType();
/* Converters */
static int convTo_WeapTypeID(const std::string&);
/* Getters */
double getReloadSpeed() const;
int getWeapTypeID() const;
int getAmmoPerShot()const;
int getMaxAmmo() const; 
std::string getWeapTypeName() const;
static WeaponType* getWeapTypeAddress(int);
};
<!-- WeaponType.cpp -->
#include "WeaponType.h"
/* Global Variables */
enum WeaponClasses {
meleeE, pistolE, machineGunE, shotgunE, sniperRifleE, explosiveE,
WeaponClasses_SizeE = explosiveE + 1
};
std::vector<std::string> weaponClassNames = 
{ "melee", "pistol", "machineGun", "shotgun", "sniperRifle", "explosive" };
enum reloadSpeeds
{
meleeRS = 0, pistolRS = 2, machineGunRS = 6,
shotgunRS = 5, sniperRifleRS = 7, explosiveRS = 30
};
enum ammoPerShots 
{
meleeAPS = 0, pistolAPS = 1, machineGunAPS = 4,
shotgunAPS = 2, sniperRifleAPS = 1, explosiveAPS = 1
};
enum maxAmmo
{
meleeMA = 1, pistolMA = 15, machineGunMA = 50,
shotgunMA = 20, sniperRifleMA = 10, explosiveMA = 3
};
bool weaponsMade = false;

/*******************
* Private Setters *
*******************/
// Maps weapTypeID to its pointer
void WeaponType::setWeapTypeAddresses (const std::vector<WeaponType*>& weapTypePtrs)
{
weapTypeAddresses[meleeE]       = weapTypePtrs[meleeE];
weapTypeAddresses[pistolE]      = weapTypePtrs[pistolE];
weapTypeAddresses[shotgunE]     = weapTypePtrs[shotgunE];
weapTypeAddresses[machineGunE]  = weapTypePtrs[machineGunE];
weapTypeAddresses[sniperRifleE] = weapTypePtrs[sniperRifleE];
weapTypeAddresses[explosiveE]   = weapTypePtrs[explosiveE];
}

/****************
* Constructors *
****************/
WeaponType::WeaponType
(int weapTypeID, double reloadSpeed, int ammoPerShot, int maxAmmo) :
reloadSpeed(reloadSpeed), ammoPerShot(ammoPerShot), maxAmmo(maxAmmo)
{
// Makes sure weapTypeID is a valid int within WeaponClasses
try
{
if (weapTypeID >= 0 && weapTypeID < WeaponClasses_SizeE) { this->weapTypeID = weapTypeID; }
else { throw weapTypeID; }
}
catch (int e)
{
std::cerr << weapTypeID << " is not a valid weapTypeID" << std::endl;
std::cerr << "Setting weapTypeID to 0" << std::endl;
this->weapTypeID = meleeE;
}
weapTypeName = weaponClassNames[weapTypeID];
}
/* This is the important constructor that needs to delete the object
that it's constructing */
WeaponType::WeaponType(int weapClassID)
{
try
{
// I need to delete the object that's being created somewhere in here
switch (weapClassID)
{
case meleeE:
*this = *WeaponType::getWeapTypeAddress(meleeE);
break;
case pistolE:
*this = *WeaponType::getWeapTypeAddress(pistolE);
break;
case machineGunE:
*this = *WeaponType::getWeapTypeAddress(machineGunE);
break;
case shotgunE:
*this = *WeaponType::getWeapTypeAddress(shotgunE);
break;
case sniperRifleE:
*this = *WeaponType::getWeapTypeAddress(sniperRifleE);
break;
case explosiveE:
*this = *WeaponType::getWeapTypeAddress(explosiveE);
break;
default:
throw weapClassID;
break;
}
}
catch (int e)
{
std::cerr
<< '"' << e << "" is not a valid "
<< "weapClassID in WeaponType::WeapType(int)"
<< std::endl;
std::cerr << "Calling destructor" << std::endl;
delete this;
}
}
// Empty constructor for reasignment
WeaponType::WeaponType() {}
void WeaponType::MakeWeaponTypes()
{
if (!weaponsMade)
{
WeaponType * melee       = new WeaponType( meleeE,       meleeRS,       meleeAPS,       meleeMA       ),
* pistol      = new WeaponType( pistolE,      pistolRS,      pistolAPS,      pistolMA      ),
* machineGun  = new WeaponType( machineGunE,  machineGunRS,  machineGunAPS,  machineGunMA  ),
* shotgun     = new WeaponType( shotgunE,     shotgunRS,     shotgunAPS,     shotgunMA     ),
* sniperRifle = new WeaponType( sniperRifleE, sniperRifleRS, sniperRifleAPS, sniperRifleMA ),
* explosive   = new WeaponType( explosiveE,   explosiveRS,   explosiveAPS,   explosiveMA   );
// Sets all the pointers to weapTypeAddresses map
std::vector<WeaponType*> weapTypePtrs =
{
melee,   pistol,      machineGun,
shotgun, sniperRifle, explosive
};
WeaponType::setWeapTypeAddresses(weapTypePtrs);
weaponsMade = true;
}
}

/*****************
* Other Methods *
*****************/
/* Destructor */
WeaponType::~WeaponType()
{
std::cout << "WeaponTypeID "" << this->weapTypeID << "" is being deleted" << std::endl;
}
/**************
* Converters *
**************/
// Converts weapTypeName to weapTypeID
int WeaponType::convTo_WeapTypeID(const std::string& className)
{
WeaponClasses weapClass;
// Makes sure className is valid
try
{
int errorCounter = 0, errorMax = 0;
for (int i = 0; i < WeaponClasses_SizeE; i++)
{
if (className != weaponClassNames[i]) { errorCounter++; }
errorMax++;  // Always increases errorMax by 1
}
if (errorCounter == errorMax) { throw 0; }
}
catch (int e)
{
std::cerr << "className parameter is invalid" << std::endl;
std::cerr << "Returning "" << weaponClassNames[0] << """ << std::endl;
return meleeE;
}
// Maps the weapTypeName to weapTypeID
std::map<std::string, WeaponClasses> Weap_ID;
Weap_ID[weaponClassNames[meleeE]]       = meleeE;
Weap_ID[weaponClassNames[pistolE]]      = pistolE;
Weap_ID[weaponClassNames[machineGunE]]  = machineGunE;
Weap_ID[weaponClassNames[shotgunE]]     = shotgunE;
Weap_ID[weaponClassNames[sniperRifleE]] = sniperRifleE;
Weap_ID[weaponClassNames[explosiveE]]   = explosiveE;
weapClass = Weap_ID[className];
return weapClass;
}

/***********
* Getters *
***********/
double WeaponType::getReloadSpeed() const { return reloadSpeed; }
int WeaponType::getWeapTypeID() const { return weapTypeID; }
int WeaponType::getAmmoPerShot() const { return ammoPerShot; }
int WeaponType::getMaxAmmo() const { return maxAmmo; }
std::string WeaponType::getWeapTypeName() const { return weapTypeName; }
WeaponType* WeaponType::getWeapTypeAddress(int weapClassID)
{
// Makes sure weapClassID is valid input
try
{
switch (weapClassID)
{
case 0:
break;
case 1:
break;
case 2:
break;
default:
throw weapClassID;
}
}
catch (int e)
{
std::cerr 
<< '"' << e << "" is not a valid "
<< "weapClassID in WeaponType::getWeapTypeAddress(int)" 
<< std::endl;
std::cerr << "Returning " << weapTypeAddresses[meleeE] << std::endl;
return weapTypeAddresses[meleeE];
}
return weapTypeAddresses[weapClassID];
}

从 武器.cpp (尚未创建(,我会有如下所示的内容: (同样,请记住,我是继承新手,代码可能不正确。

<!-- Pre-file of Weapon.cpp -->
#include "Weapon.h"
#include "WeaponType.h"
Weapon::Weapon(std::string weapName, double damage, int ammo, int weapTypeID) : 
WeaponType::WeaponType(weapTypeID)
{
this->damage = damage;
this->ammo = ammo;
}

最后,一个基本的主方法

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include "WeaponType.h"
#include "Weapon.h"
using namespace std;
int main()
{
string gunName = "pistolGun";
double gunDamage = 10.0;
int gunAmmo = 20;
int weapTypeID = 1; 
// Creates a pistolGun object.
Weapon pistolGun (gunGame, gunDamage, gunAmmo, weapTypeID);
// The goal is to get the WeaponType* of pistolGun to equal &pistol from WeaponType.
// That would mean these who lines of code output the same address.
// Also note: I know this code to reference these addresses is incorrect
cout << "Address of WeaponType attributes of pistolGun: " << &pistolGun.WeaponTypeAttribs << endl;
cout << "Address of pistol WeaponType: " &pistol << endl;
}

根据我的理解,你正在使用WeaponType来存储所有特征,而武器代表游戏中的实际对象,所以它有一个类型,但它也有弹药或世界上的位置之类的东西。

与其将此关系建模为"武器是-武器类型",不如考虑将其建模为"武器具有-武器类型"。将链接的代码减少到合理的水平,这样的方法可能会更好:

#include<string>
#include<memory>
class WeaponType
{
public:
double reloadSpeed;
int weapTypeID, ammoPerShot, maxAmmo;
std::string weapTypeName;
};
class Weapon
{
public:
explicit Weapon(std::shared_ptr<const WeaponType> type)
: type(std::move(type))
{
ammo = this->type->maxAmmo;
}
const std::shared_ptr<const WeaponType> type;
int ammo;
};
int main()
{
// make the weapon types
auto pistolType     = std::make_shared<WeaponType>(WeaponType{ 1.0, 0, 1, 20, "pistol" });
auto machineGunType = std::make_shared<WeaponType>(WeaponType{ 5.0, 1, 1, 100, "machine gun" });
// ...etc
// Create some actual weapon objects out of those types
auto pistolGun1 = Weapon{ pistolType };
auto pistolGun2 = Weapon{ pistolType };
auto machineGun1 = Weapon{ machineGunType };
auto machineGun2 = Weapon{ machineGunType };
}

最新更新