保存和检索具有const成员变量的对象的内容(进出磁盘文件)的方法是什么? 或者更具体地说,const成员要求在对象的创建时进行初始化。因此,内容的检索必须在初始化器之前(构造函数的{}之前)进行。如果我们不关注封装,我们可以使用参数检索和创建对象。如何通过保持数据隐藏来做所有事情?
编译器:C ++ 14,可能还有更多。
实例化对象,填充内容并存储下一个上下文。
{ //CODE BLOCK 1 : making of content and saving to a diskfile
Abcd abcd(65535,256,25);
//some operations on abcd
//save to disk
QFile abcdFile("abcd.lion");
abcdFile.open(QFile::WriteOnly);
abcd.serialize(abcdFile);
abcdFile.close();
}
从文件中取出后使用相同的对象。
{ //CODE BLOCK 2 : loading from file and continue in another context
QFile abcdFile("abcd.lion");
abcdFile.open(QFile::ReadOnly);
Abcd abcdNew(abcdFile);
abcdFile.close();
if(!abcdNew.isHealthy())
printf("abcd from hdd is NOT Healthy :(\n");
else
{
//doTheJob(abcdNew);
}
}
班级。
#include <QFile>
class Abcd
{
const bool _healthy;//true if properly initialized
//IMPORTANT: _healthy has to be the first member in the class.
//this is to execute its initializer list first
protected:
const long _rX;
const long _rY;
long _count;
public:
Abcd(const long refX,
const long refY,
const long count) :
_healthy(true),
_rX(refX), _rY(refY),
_count(count)
{
}
Abcd(QFile &src) :
_healthy(deserialize(src)),
//Hack. Actually the initialization happened by this statement.
//just keeping the below statements for the sake of syntactical correctness. :(
_rX(_rX), _rY(_rY)
//,_count(count)
{
}
virtual
~Abcd()
{
}
inline
bool isHealthy()
{
return _healthy;
}
bool serialize(QFile &dest)
{
if(dest.write((char *)&_rY,sizeof(_rY))!=sizeof(_rY)) return false;
if(dest.write((char *)&_rX,sizeof(_rX))!=sizeof(_rX)) return false;
if(dest.write((char *)&_count,sizeof(_count))!=sizeof(_count)) return false;
return true;
}
private:
bool deserialize(QFile &src)
{
if(src.read((char *)&_rY,sizeof(_rY))!=sizeof(_rY)) return false;
if(src.read((char *)&_rX,sizeof(_rX))!=sizeof(_rX)) return false;
if(src.read((char *)&_count,sizeof(_count))!=sizeof(_count)) return false;
return true;
}
};
请建议一个更好的方法。为此,我引入了一个“健康”状态成员作为该类声明中的第一个成员。同样在反序列化中,我通过将const变量强制转换为char *指针来欺骗编译器。
我的建议是将Abcd和序列化/反序列化的逻辑分成两类。
优点:
_healthy
作为对象总是有效的设计。Abcd
只做一份工作。没有任何存储逻辑(单一责任)几点提示:
const
字段只是使对象不能复制/移动可分配(无法与容器等一起使用)。只需正确使用const正确性即可确保不变性。class Abcd final
{
public:
Abcd(const long refX, const long refY, const long count)
: _rX(refX)
, _rY(refY)
, _count(count)
{
}
long GetRX() const
{
return _rX;
}
long GetRY() const
{
return _rY;
}
long GetCount() const
{
return _count;
}
protected:
long _rX;
long _rY;
long _count;
};
#include <boost/optional.hpp>
#include <QFile>
template <typename T>
using Opt = boost::optional<T>; // or equivalent
// Choose better name for Serializer or even split it up
class AbcdSerializer final
{
public:
AbcdSerializer(QFile& file)
: _file(file)
{
}
// You may also throw an exception instead of returning optional
Opt<Abcd> TryDeserializeAbcd()
{
long rX;
long rY;
long count;
if (ReadValue(rY) && ReadValue(rX) && ReadValue(count))
{
return Abcd(rX, rY, count);
}
return {};
}
bool SerializeAbcd(const Abcd& abcd)
{
return WriteValue(abcd.GetRY()) && WriteValue(abcd.GetRX()) && WriteValue(abcd.GetCount());
}
private:
template <typename T>
bool ReadValue(T& value)
{
constexpr auto ValueSize = sizeof(value);
return _file.read(reinterpret_cast<char*>(&value), ValueSize) != ValueSize;
}
template <typename T>
bool WriteValue(const T& value)
{
constexpr auto ValueSize = sizeof(value);
return _file.write(reinterpret_cast<const char*>(&value), ValueSize) != ValueSize;
}
QFile& _file;
};
我的建议是使用类的static
成员函数从磁盘检索文件的内容,并在成功检索内容后构造一个对象。
代替:
Abcd(QFile &src) :
使用
static Abcd deserialize(QFile& src);
并实现它:
Abcd Abcd::deserialize(QFile& src)
{
long rX;
long rY;
long count;
if(src.read((char *)&rY, sizeof(rY)) != sizeof(rY)) throw false;
if(src.read((char *)&rX, sizeof(rX)) != sizeof(rX)) throw false;
if(src.read((char *)&count, sizeof(count)) != sizeof(count)) throw false;
return Abcd(rX, rY, count):
}
PS首先保存_rY
然后_rX
,这很奇怪。没有错,这很奇怪。