C++ 属性类

时间:2023-04-19 10:48:26

又一次向目标迈进了...

这次是实现一个物体所拥有的属性类。没什么好说的,非常简单。

因为我是C++新手,不知道对这次的实现有没有什么更好的实现方式。因为这个类对以后的进展很重要,而且,要充分考虑易用性,安全性,以及扩展性……

emmmmmmm................

1.潜在BUG:这种依靠加减来对属性进行回滚的方式无疑是大胆的。对于属性值为整数情况还好说,如果是小数,这势必会造成误差,而这种误差如果不修改算法难以避免。目前想到的也只有装饰器模式和状态机。使用前者,那么与现在的情况没什么两样;使用后者能够准确回滚属性值,但会造成极大的内存代价。还没有什么好的解决方式我能想起来的。但,被修改是迟早的事情。(2018.10.30 17:01)

2.BUGFIX:

2.1 增加了Get函数。(2018.11.1 19:20)

Quality.h

#pragma once

#include "stdinc.h"
#include "Rational.h" #include "QualDefine.h" namespace Lunacia
{
/*The base quality class.*/
class Quality
{
protected:
/*Only class QualitiesManager can instantiate it.*/
Quality() = delete;
Quality(QualityType type); virtual ~Quality(); public:
Quality& operator=(const Quality&) = delete; public:
void SetValue(int32_t val, bool isForce = false);
void AddValue(int32_t inc);
int32_t GetValue() const; QualityType GetType() const; void SetLimit(int32_t max);
int32_t GetLimit(); bool AddPassive(Quality*const & passive);
bool RemovePassive(QualityType type);
bool RebackPassiveValue(QualityType type);
void RebackAllPassiveValue(); bool Cut(Quality*& otherQual); virtual void Clear();
static void Clear(Quality*& pQual); protected:
virtual Rational<int32_t> PassiveImpact(const Quality*const & active) = 0; /*Notify all passives when the value is modified.*/
void NotifyAll();
void SetType(QualityType type); protected:
QualityType m_type;
Rational<int32_t> m_value; std::unordered_map<QualityType, Quality* const > m_passives;
std::unordered_map<QualityType, Rational<int32_t>> m_passivesValue;
}; typedef Quality*const & PtrQuality;
};

Quality.cpp

#include "Quality.h"

namespace Lunacia
{
Quality::Quality(QualityType type):
m_type(type)
{
m_value(0, 1000);
m_value.SetDenomFixed(false);
} Quality::~Quality()
{
Clear();
} void Quality::SetValue(int32_t val, bool isForce)
{
int32_t& selfVal = m_value._numer;
selfVal = val; if (selfVal > m_value._denom)
{
selfVal = m_value._denom;
} if (selfVal < 0)
{
selfVal = 0;
} if(!isForce) NotifyAll();
} void Quality::AddValue(int32_t inc)
{
SetValue(inc += m_value._numer, false);
} int32_t Quality::GetValue() const
{
return m_value._numer;
} QualityType Quality::GetType() const
{
return m_type;
} void Quality::SetType(QualityType type)
{
m_type = type;
} void Quality::SetLimit(int32_t max)
{
if (max <= 0) return; const float insRatio = max * 1.0f / m_value._denom; m_value._denom = max;
if (m_value > 1)
{
m_value._numer = max;
}
else
{
m_value._numer = static_cast<int32_t>(insRatio * m_value._numer);
}
} int32_t Quality::GetLimit()
{
return m_value._denom;
} bool Quality::AddPassive(Quality*const & passive)
{
if (passive == nullptr)
{
return false;
} bool res2 = m_passives.insert(std::pair(passive->m_type, passive)).second; Rational<int32_t> pv(0, 0);
bool res1 = m_passivesValue.insert(std::pair(passive->m_type, pv)).second; return res2;
} bool Quality::RemovePassive(QualityType type)
{
RebackPassiveValue(type); m_passivesValue.erase(type);
return m_passives.erase(type) == 1;
} bool Quality::RebackPassiveValue(QualityType type)
{
auto itFound_pv = m_passivesValue.find(type);
auto itFound = m_passives.find(type); if (itFound_pv == m_passivesValue.end() ||
itFound == m_passives.end())
{
return false;
} Rational<int32_t>& pvVal = itFound_pv->second;
itFound->second->SetLimit(itFound->second->m_value._denom -= pvVal._denom);
itFound->second->AddValue(pvVal._numer * -1); pvVal(0, 0);
return true;
} void Quality::RebackAllPassiveValue()
{
for (auto itEach : m_passives)
{
RebackPassiveValue(itEach.second->GetType());
}
} bool Quality::Cut(Quality *& otherQual)
{
if (otherQual == nullptr || (m_type != otherQual->GetType()))
{
return false;
} m_value = otherQual->GetValue();
m_passives = otherQual->m_passives;
m_passivesValue = otherQual->m_passivesValue; Quality::Clear(otherQual);
return true;
} void Quality::Clear()
{
m_passives.clear();
m_passivesValue.clear();
m_value = 0;
} void Quality::Clear(Quality *& pQual)
{
if (pQual == nullptr)
{
return;
}
pQual->Clear();
delete pQual;
pQual = nullptr;
} void Quality::NotifyAll()
{
for (auto& each : m_passives)
{
Quality* const& passive = each.second;
if (passive != nullptr)
{
Rational<int32_t> pv = passive->PassiveImpact(this);
if (pv._denom != 0 || pv._numer != 0)
{
Rational<int32_t>& pvEach = m_passivesValue[each.first];
pvEach._denom += pv._denom;
pvEach._numer += pv._numer;
}
}
}
} };

QualitiesManager.h

#pragma once
#include "Quality.h" namespace Lunacia
{
class QualitiesManager
{
#ifdef __Debug
public:
#else
private:
#endif // __Debug
QualitiesManager();
QualitiesManager(uint8_t qualInitCount);
~QualitiesManager(); static QualitiesManager* CreateQualManager(uint8_t qualInitCount = 10);
static void DestoryQualManager(QualitiesManager* pQualManager); public:
friend class LunaObject; void Clear(); public:
Quality* const& AddQuality(Quality* pQual, bool isCover = false); template<class T, typename std::enable_if <std::is_base_of<Quality, T>::value, T> ::type * = nullptr >
Quality* const& AddQuality(); bool RemoveQuality(QualityType type);
void RemoveAll(); //void DestoryQuality(Quality*& pQual); template<class T, typename std::enable_if <std::is_base_of<Quality, T>::value, T> ::type * = nullptr >
Quality* const CreateQuality(); const Quality* const GetQuality(QualityType type) const;
Quality* const FindQuality(QualityType type); private:
std::unordered_map<QualityType, Quality* > m_qualities;
}; ////////////////////////////////////////////////////////////////////////////////////////////////////
//inline void QualitiesManager::DestoryQuality(Quality*& pQual)
//{
// Quality::Clear(pQual);
//} template<class T, typename std::enable_if <
std::is_base_of<Quality, T>::value,
T> ::type *>
inline Quality * const QualitiesManager::CreateQuality()
{
return new T();
} template<class T, typename std::enable_if <
std::is_base_of<Quality, T>::value,
T> ::type *>
Quality * const& QualitiesManager::AddQuality()
{
return AddQuality(CreateQuality<T>());
}
};

QualitiesManager.cpp

#include "QualitiesManager.h"

namespace Lunacia
{
QualitiesManager::QualitiesManager()
{
m_qualities.reserve(10);
} QualitiesManager::QualitiesManager(uint8_t qualInitCount)
{
m_qualities.reserve(qualInitCount);
} QualitiesManager::~QualitiesManager()
{
Clear();
} QualitiesManager * QualitiesManager::CreateQualManager(uint8_t qualInitCount)
{
return new QualitiesManager(qualInitCount);
} void QualitiesManager::DestoryQualManager(QualitiesManager * pQualManager)
{
pQualManager->Clear(); delete pQualManager;
pQualManager = nullptr;
} void QualitiesManager::Clear()
{
for (auto& each : m_qualities)
{
Quality::Clear(each.second);
}
m_qualities.clear();
} Quality* const& QualitiesManager::AddQuality(Quality* pQual, bool isCover)
{
QualityType type = pQual->GetType();
auto itFound = m_qualities.find(type); if (itFound != m_qualities.end())
{
Quality* &qual = itFound->second;
if (isCover)
qual->Cut(pQual);
else
qual->AddValue(pQual->GetValue()); return qual;
} return m_qualities.insert(std::pair(type, pQual)).first->second;
} bool QualitiesManager::RemoveQuality(QualityType type)
{
auto found = m_qualities.find(type);
Quality* qualFound = (found == m_qualities.end()) ? nullptr : found->second; for (auto& each : m_qualities)
{
each.second->RemovePassive(type);
} Quality::Clear(qualFound);
return m_qualities.erase(type) == 1;
} void QualitiesManager::RemoveAll()
{
Clear();
} const Quality * const QualitiesManager::GetQuality(QualityType type) const
{
auto itFound = m_qualities.find(type);
if (itFound == m_qualities.end())
{
return nullptr;
}
return itFound->second;
} Quality * const QualitiesManager::FindQuality(QualityType type)
{
Quality * const res = const_cast<Quality * const>(GetQuality(type));
return res;
}
};

*以下文件为测试用文件。

QualHealth.cpp

#include "QualHealth.h"

namespace Lunacia
{
QualHealth::QualHealth()
:Quality(QualityType::HEALTH)
{ } QualHealth::~QualHealth()
{ } void QualHealth::PassiveImpact(const Quality * const & active)
{
if (active == nullptr) return; int32_t val = active->GetValue();
switch (active->GetType())
{
case QualityType::LIFE_INSTINCT:
m_value._numer += static_cast<int32_t>(val * g_rn.GetRandNum<float>()); //test.
break; default:
break;
} } };

QualHealth.h

#pragma once

#include "Quality.h"

namespace Lunacia
{
class QualHealth final : public Quality
{
public:
QualHealth();
~QualHealth(); private:
void PassiveImpact(const Quality*const& active); };
};

QualLifeInstinct.cpp

#include "QualLifeInstinct.h"

namespace Lunacia
{
QualLifeInstinct::QualLifeInstinct()
:Quality(QualityType::LIFE_INSTINCT)
{
SetValue(500);
} QualLifeInstinct::~QualLifeInstinct()
{
} void QualLifeInstinct::PassiveImpact(const Quality * const & active)
{
//Nothing here...
return;
} };

QualLifeInstinct.h

#pragma once

#include "Quality.h"
namespace Lunacia
{
class QualLifeInstinct final : public Quality
{
public:
QualLifeInstinct();
~QualLifeInstinct(); private:
void PassiveImpact(const Quality*const & active);
}; };

main.cpp

#include "Tilee.h"
#include "Location.h"
#include "stdinc.h"
#include "Random.h"
#include "Rational.h"
#include "QualitiesManager.h"
#include "QualHealth.h"
#include "QualLifeInstinct.h" using namespace Lunacia; struct Item
{
uint32_t weight;
int id;
}; int main(void)
{
//QualHealth
QualitiesManager qm;
PtrQuality ptrQualHealth = qm.AddQuality<QualHealth>();
PtrQuality ptrQualHealth2 = qm.AddQuality<QualHealth>(); PtrQuality ptrQualLifeIns = qm.AddQuality<QualLifeInstinct>(); ptrQualLifeIns->AddPassive(ptrQualHealth); ptrQualHealth->AddValue(100);
ptrQualHealth2->SetValue(432); ptrQualLifeIns->AddValue(10); qm.RemoveQuality(ptrQualHealth->GetType()); RandomNorm rn(0.6, 0.15);
for (size_t i = 0; i < 100; i++)
{
std::cout << rn.GetRandNum() << std::endl;
} system("pause");
return 0;
}

对于漫长的编译时间,我应该仔细考虑一下代码结构了。

下一个,物体类(object class)。