序列化和反序列化
实现思路:
- 序列化 :将对象的状态信息转换为可以存储或传输的格式,通常是字节流。
- 确定要序列化的对象的数据成员。
- 将这些数据成员按照一定的规则(如二进制、文本、JSON、XML 等)编码为字节序列。
- 将生成的字节序列存储到文件或发送到网络。
- 反序列化 :将字节流恢复为对象的状态信息。
- 从文件或网络接收字节序列。
- 按照序列化时使用的规则解码字节序列。
- 根据解码后的数据成员创建或更新对象。
cpp
#include <iostream>
#include <fstream>
#include <string>
class SerializableObject {
private:
int data1;
double data2;
std::string data3;
public:
SerializableObject(int d1 = 0, double d2 = 0.0, const std::string& d3 = "") : data1(d1), data2(d2), data3(d3) {}
// 序列化函数
void serialize(const std::string& filename) const {
std::ofstream file(filename, std::ios::binary);
if (file.is_open()) {
// 写入数据成员
file.write(reinterpret_cast<const char*>(&data1), sizeof(data1));
file.write(reinterpret_cast<const char*>(&data2), sizeof(data2));
// 先写入字符串长度
size_t len = data3.length();
file.write(reinterpret_cast<const char*>(&len), sizeof(len));
// 再写入字符串内容
file.write(data3.c_str(), len);
file.close();
} else {
std::cerr << "Failed to open file for serialization." << std::endl;
}
}
// 反序列化函数
void deserialize(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
if (file.is_open()) {
// 读取数据成员
file.read(reinterpret_cast<char*>(&data1), sizeof(data1));
file.read(reinterpret_cast<char*>(&data2), sizeof(data2));
// 先读取字符串长度
size_t len;
file.read(reinterpret_cast<char*>(&len), sizeof(len));
// 再读取字符串内容
data3.resize(len);
file.read(&data3[0], len);
file.close();
} else {
std::cerr << "Failed to open file for deserialization." << std::endl;
}
}
void display() const {
std::cout << "data1: " << data1 << ", data2: " << data2 << ", data3: " << data3 << std::endl;
}
};
int main() {
SerializableObject obj(42, 3.14, "Hello, World!");
std::string filename = "object.bin";
// 序列化
obj.serialize(filename);
std::cout << "Serialized object: " << std::endl;
obj.display();
SerializableObject newObj;
// 反序列化
newObj.deserialize(filename);
std::cout << "Deserialized object: " << std::endl;
newObj.display();
return 0;
}
代码解释:
SerializableObject
类包含三个数据成员:data1
(整数)、data2
(双精度浮点数)和data3
(字符串)。serialize
函数:- 使用
std::ofstream
以二进制模式打开文件。 - 对于
data1
和data2
,使用file.write
将它们的二进制表示写入文件。 - 对于
data3
,先写入字符串的长度,再写入字符串的内容。
- 使用
deserialize
函数:- 使用
std::ifstream
以二进制模式打开文件。 - 对于
data1
和data2
,使用file.read
读取它们的二进制表示。 - 对于
data3
,先读取字符串的长度,再读取字符串的内容。
- 使用
display
函数:打印对象的数据成员。
如何处理对象的生命周期管理?
实现思路:
- 构造函数:用于对象的初始化,可进行资源分配和成员初始化。
- 析构函数:用于对象销毁时释放资源,如释放动态分配的内存、关闭文件等。
- 拷贝构造函数和拷贝赋值运算符:控制对象的拷贝行为,避免浅拷贝导致的资源问题。
- 移动构造函数和移动赋值运算符:实现对象资源的高效移动,避免不必要的拷贝。
cpp
#include <iostream>
#include <string>
#include <utility>
class ResourceManagingObject {
private:
int* data;
size_t size;
public:
// 构造函数
ResourceManagingObject(size_t s = 0) : size(s) {
if (s > 0) {
data = new int[s];
for (size_t i = 0; i < s; ++i) {
data[i] = i;
}
} else {
data = nullptr;
}
}
// 析构函数
~ResourceManagingObject() {
delete[] data;
}
// 拷贝构造函数
ResourceManagingObject(const ResourceManagingObject& other) : size(other.size) {
if (other.data) {
data = new int[size];
for (size_t i = 0; i < size; ++i) {
data[i] = other.data[i];
}
} else {
data = nullptr;
}
}
// 拷贝赋值运算符
ResourceManagingObject& operator=(const ResourceManagingObject& other) {
if (this == &other) return *this;
delete[] data;
size = other.size;
if (other.data) {
data = new int[size];
for (size_t i = 0; i < size; ++i) {
data[i] = other.data[i];
}
} else {
data = nullptr;
}
return *this;
}
// 移动构造函数
ResourceManagingObject(ResourceManagingObject&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
// 移动赋值运算符
ResourceManagingObject& operator=(ResourceManagingObject&& other) noexcept {
if (this == &other) return *this;
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
return *this;
}
void display() const {
if (data) {
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
} else {
std::cout << "No data." << std::endl;
}
}
};
int main() {
ResourceManagingObject obj1(5);
std::cout << "Original object: ";
obj1.display();
// 拷贝构造
ResourceManagingObject obj2 = obj1;
std::cout << "Copied object: ";
obj2.display();
// 移动构造
ResourceManagingObject obj3 = std::move(obj1);
std::cout << "Moved object: ";
obj3.display();
std::cout << "Original object after move: ";
obj1.display();
return 0;
}
代码解释:
ResourceManagingObject
类管理一个动态分配的整数数组。- 构造函数:根据大小分配内存并初始化数组元素。
- 析构函数:释放动态分配的内存。
- 拷贝构造函数和拷贝赋值运算符:深拷贝资源,避免浅拷贝导致的资源共享和潜在的内存问题。
- 移动构造函数和移动赋值运算符:将资源从源对象移动到目标对象,源对象放弃资源所有权。