什么是java.io.Serializable的C/C++等价?

alv*_*vas 10 c c++ java serialization

什么是java.io.Serializable的C/C++等价?

有关序列化库的参考:

还有:

但这样的等价甚至存在吗?

因此,如果我在Java中有如下的抽象类,那么C/C++中的可序列化类是什么样的?

import java.io.Serializable;

public interface SuperMan extends Serializable{

    /**
     * Count the number of abilities.
     * @return
     */
    public int countAbility();

    /**
     * Get the ability with index k.
     * @param k
     * @return
     */
    public long getAbility(int k);

    /**
     * Get the array of ability from his hand.
     * @param k
     * @return
     */
    public int[] getAbilityFromHand(int k);

    /**
     * Get the finger of the hand.
     * @param k
     * @return
     */
    public int[][] getAbilityFromFinger(int k);

    //check whether the finger with index k is removed.
    public boolean hasFingerRemoved(int k);

    /**
     * Remove the finger with index k.
     * @param k
     */
    public void removeFinger(int k);

}
Run Code Online (Sandbox Code Playgroud)

可以像Java一样继承任何可序列化的C/C++对象吗?

Gal*_*lik 13

没有标准的库类以相同的方式实现序列化Java.有一些库可以促进序列化,但是对于基本需求,您通常可以通过重载插入提取操作符来使类可序列化,如下所示:

class MyType
{
    int value;
    double factor;
    std::string type;

public:
    MyType()
    : value(0), factor(0.0), type("none") {}
    MyType(int value, double factor, const std::string& type)
    : value(value), factor(factor), type(type) {}

    // Serialized output
    friend std::ostream& operator<<(std::ostream& os, const MyType& m)
    {
        return os << m.value << ' ' << m.factor << ' ' << m.type;
    }

    // Serialized input
    friend std::istream& operator>>(std::istream& is, MyType& m)
    {
        return is >> m.value >> m.factor >> m.type;
    }
};

int main()
{
    std::vector<MyType> v {{1, 2.7, "one"}, {4, 5.1, "two"}, {3, 0.6, "three"}};

    std::cout << "Serialize to standard output." << '\n';

    for(auto const& m: v)
        std::cout << m << '\n';

    std::cout << "\nSerialize to a string." << '\n';

    std::stringstream ss;
    for(auto const& m: v)
        ss << m << '\n';

    std::cout << ss.str() << '\n';

    std::cout << "Deserialize from a string." << '\n';

    std::vector<MyType> v2;

    MyType m;
    while(ss >> m)
        v2.push_back(m);

    for(auto const& m: v2)
        std::cout << m << '\n';

}
Run Code Online (Sandbox Code Playgroud)

输出:

Serialize to standard output.
1 2.7 one
4 5.1 two
3 0.6 three

Serialize to a string.
1 2.7 one
4 5.1 two
3 0.6 three

Deserialize from a string.
1 2.7 one
4 5.1 two
3 0.6 three
Run Code Online (Sandbox Code Playgroud)

序列化格式是完全由程序员,您有责任确保您要的类的每一个成员序列化本身是序列化(具有插入/拔出定义的运营商).您还必须处理字段如何分隔(空格或换行或零终止?).

所有基本类型都预先定义了序列化(插入/提取)运算符,但您仍需要注意std::string可能包含(例如)空格或换行符(如果您使用空格或换行符作为字段)分隔符).


Dan*_*ski 5

对此没有统一的标准。实际上,每个库都可以以不同的方式实现它。以下是一些可以使用的方法:

  • 类必须从通用基类,实现read()write()虚拟方法派生:

    class SuperMan : public BaseObj
    {
    public:
        virtual void read(Stream& stream);
        virtual void write(Stream& stream);
    };
    
    Run Code Online (Sandbox Code Playgroud)
  • 类应该实现特殊的接口-在C ++中,这是通过从特殊的抽象类派生类来完成的。这是先前方法的变化:

    class Serializable
    {
    public:
        virtual Serializable() {}
        virtual void read(Stream& stream) = 0;
        virtual void write(Stream& stream) = 0;
    };
    
    class SuperMan : public Man, public Serializable
    {
    public:
        virtual void read(Stream& stream);
        virtual void write(Stream& stream);
    };
    
    Run Code Online (Sandbox Code Playgroud)
  • 库可能允许(或要求)为给定类型注册“序列化器”。可以通过从特殊的基类或接口创建类,然后为给定类型注册它们来实现它们:

    #define SUPERMAN_CLASS_ID 111
    
    class SuperMan
    {
    public:
        virtual int getClassId()
        {
            return SUPERMAN_CLASS_ID;
        }
    };
    
    class SuperManSerializer : public Serializer
    {
        virtual void* read(Stream& stream);
        virtual void write(Stream& stream, void* object);
    };
    
    int main()
    {
        register_class_serializer(SUPERMAN_CLASS_ID, new SuperManSerializer());
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 序列化器也可以使用函子来实现,例如lambdas:

    int main
    {
        register_class_serializer(SUPERMAN_CLASS_ID,
                                  [](Stream&, const SuperMan&) {},
                                  [](Stream&) -> SuperMan {});
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 无需将序列化程序对象传递给某些函数,只需将其类型传递给特殊的模板函数即可:

    int main
    {
        register_class_serializer<SuperManSerializer>();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 类应提供重载的运算符,例如“ <<”和“ >>”。它们的第一个参数是某个流类,第二个参数是out类实例。Stream可以是std::stream,但是这会与这些运算符的默认用法冲突-转换为用户友好的文本格式或从中转换。因为这个流类是专用的(它可以包装std :: stream),否则,如果<<还必须支持库,它将支持替代方法。

    class SuperMan
    {
    public:
        friend Stream& operator>>(const SuperMan&);
        friend Stream& operator<<(const SuperMan&);
    };
    
    Run Code Online (Sandbox Code Playgroud)
  • 对于我们的类类型,应该有一些类模板的特殊化。此解决方案可以与<<>>运算符一起使用-库首先会尝试使用此模板,如果不专门化,则还原为运算符(可以将其实现为默认模板版本,也可以使用SFINAE来实现)

    // default implementation
    template<class T>
    class Serializable
    {
    public:
        void read(Stream& stream, const T& val)
        {
            stream >> val;
        }
        void write(Stream& stream, const T& val)
        {
            stream << val;
        }
    };
    
    // specialization for given class
    template<>
    class Serializable<SuperMan>
    {
        void read(Stream& stream, const SuperMan& val);
        void write(Stream& stream, const SuperMan& val);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 代替类模板库,也可以使用带有全局重载函数的C样式接口:

    template<class T>
    void read(Stream& stream, const T& val);
    template<class T>
    void write(Stream& stream, const T& val);
    
    template<>
    void read(Stream& stream, const SuperMan& val);
    template<>
    void write(Stream& stream, const SuperMan& val);
    
    Run Code Online (Sandbox Code Playgroud)

C ++语言是灵活的,因此上面所列内容肯定不完整。我坚信有可能发明另一种解决方案。