Serializing member function pointers directly is not recommended because they contain implementation-specific memory addresses. Instead, we should serialize an identifier that can be mapped back to the appropriate function.
Here's how to implement this safely using an enum:
#include <iostream>
#include <map>
class Character {
public:
enum class AbilityType {
Fireball,
IceBlast,
Lightning
};
using AbilityFunc = void (Character::*)();
void Fireball() {
std::cout << "Cast Fireball!\n";
}
void IceBlast() {
std::cout << "Cast Ice Blast!\n";
}
void Lightning() {
std::cout << "Cast Lightning!\n";
}
// Map ability types to member functions
static std::map<AbilityType, AbilityFunc>
AbilityMap;
// Serialize ability to enum
AbilityType
SerializeAbility(AbilityFunc Func) {
for (const auto& [type, ptr] : AbilityMap) {
if (ptr == Func) return type;
}
throw std::runtime_error("Unknown ability");
}
// Deserialize enum to ability
AbilityFunc
DeserializeAbility(AbilityType Type) {
return AbilityMap[Type];
}
};
// Initialize static map
std::map<Character::AbilityType,
Character::AbilityFunc>
Character::AbilityMap =
{
{AbilityType::Fireball, &Character::Fireball},
{AbilityType::IceBlast, &Character::IceBlast},
{
AbilityType::Lightning,
&Character::Lightning}};
int main() {
Character player;
// Store current ability
auto currentAbility = &Character::Fireball;
// Serialize
auto serialized = player.SerializeAbility(
currentAbility);
// Save to file/network (example just prints)
std::cout << "Saved ability ID: " <<
static_cast<int>(serialized) << '\n';
// Load and deserialize
auto loadedAbility = player.
DeserializeAbility(serialized);
// Use restored ability
(player.*loadedAbility)();
}
Saved ability ID: 0
Cast Fireball!
In this variation, we use a std::string
:
#include <iostream>
#include <map>
#include <string>
class Character {
public:
using AbilityFunc = void (Character::*)();
void Fireball() {
std::cout << "Cast Fireball!\n";
}
void IceBlast() {
std::cout << "Cast Ice Blast!\n";
}
private:
static std::map<std::string, AbilityFunc>
AbilityMap;
public:
std::string
SerializeAbility(AbilityFunc Func) {
for (const auto& [name, ptr] : AbilityMap) {
if (ptr == Func) return name;
}
return "unknown";
}
AbilityFunc DeserializeAbility(
const std::string& Name) {
auto it = AbilityMap.find(Name);
if (it != AbilityMap.end()) {
return it->second;
}
throw std::runtime_error(
"Unknown ability: " + Name);
}
};
// Initialize static map
std::map<std::string, Character::AbilityFunc>
Character::AbilityMap = {
{"fireball", &Character::Fireball},
{"ice_blast", &Character::IceBlast}};
int main() {
Character player;
// Serialize
auto serialized = player.SerializeAbility(
&Character::Fireball);
std::cout << "Saved ability name: " <<
serialized << '\n';
// Deserialize and use
auto loadedAbility = player.
DeserializeAbility(serialized);
(player.*loadedAbility)();
}
Saved ability name: fireball
Cast Fireball!
Key considerations:
This approach ensures safe serialization while maintaining the flexibility of member function pointers.
Answers to questions are automatically generated and may not have been reviewed.
Learn how to create pointers to class functions and data members, and how to use them