为什么虚拟功能打破了我的铸造

Why does a virtual function break my casting?

本文关键字:我的 虚拟 功能 为什么      更新时间:2023-10-16

我正在努力扩展以下代码:

#include <iostream>
class XmlTree {};
class Base
{
protected:
    int var;
public:
    Base(int var) : var(var) {}
    virtual ~Base() {}
};
class Derived : public Base
{
public:
    void SerializeTo(XmlTree& tree) const { std::cout << var << std::endl; }
    void DeserializeFrom(const XmlTree& tree) { var = 2; }
};
void operator<<(XmlTree& tree, const Base& b) { static_cast<const Derived&>(b).SerializeTo(tree); }
void operator>>(const XmlTree& tree, Base& b) { static_cast<Derived&>(b).DeserializeFrom(tree); }
int main() {
    Base b(1);
    XmlTree tree;
    tree << b;
    tree >> b;
    tree << b;
}

此代码正常运行,并按照预期打印'1',然后打印'2'。

但是现在我想实现这样的接口:

class XmlInterface
{
public:
    virtual void SerializeTo(XmlTree& tree) const = 0;
    virtual void DeserializeFrom(const XmlTree& tree) = 0;
};
class Derived : public Base, public XmlInterface
{
public:
    virtual void SerializeTo(XmlTree& tree) const override { std::cout << var << std::endl; }
    virtual void DeserializeFrom(const XmlTree& tree) override { var = 2; }
};

tl; dr:如何使它起作用?

我试图使用Dynamic_cast和虚拟破坏者来制作类多态性。我还试图实现从基地到派生的解释降低的构造函数,但我失败了。

ps:更改"基础"不是一个选择。

b不是 Derived对象,因此将其施放给Derived不确定的行为

在第一个示例中,正确的解决方案是将序列化方法移动到Base中,并使它们虚拟/抽象使Derived可以覆盖它们。然后创建一个Derived对象,然后从操作员中删除铸件:

#include <iostream>
class XmlTree {};
class Base
{
protected:
    int var;
public:
    Base(int var) : var(var) {}
    virtual ~Base() {}
    virtual void SerializeTo(XmlTree& tree) const = 0;
    virtual void DeserializeFrom(const XmlTree& tree) = 0;
};
class Derived : public Base
{
public:
    Derived(int var) : Base(var) {}
    void SerializeTo(XmlTree& tree) const override { std::cout << var << std::endl; }
    void DeserializeFrom(const XmlTree& tree) override { var = 2; }
};
void operator<<(XmlTree& tree, const Base& b) { b.SerializeTo(tree); }
void operator>>(const XmlTree& tree, Base& b) { b.DeserializeFrom(tree); }
int main() {
    Derived d(1);
    XmlTree tree;
    tree << d;
    tree >> d;
    tree << d;
}

在第二个示例中做类似的事情:

#include <iostream>
class XmlTree {};
class Base
{
protected:
    int var;
public:
    Base(int var) : var(var) {}
    virtual ~Base() {}
};
class XmlInterface
{
public:
    virtual void SerializeTo(XmlTree& tree) const = 0;
    virtual void DeserializeFrom(const XmlTree& tree) = 0;
};
class Derived : public Base, public XmlInterface
{
public:
    Derived(int var) : Base(var) {}
    void SerializeTo(XmlTree& tree) const override { std::cout << var << std::endl; }
    void DeserializeFrom(const XmlTree& tree) override { var = 2; }
};
void operator<<(XmlTree& tree, const XmlInterface& intf) { intf.SerializeTo(tree); }
void operator>>(const XmlTree& tree, XmlInterface& intf) { intf.DeserializeFrom(tree); }
int main() {
    Derived d(1);
    XmlTree tree;
    tree << d;
    tree >> d;
    tree << d;
}

b定义为Base类型和调用操作员<<时,将操作数施加到Derived&时,您会产生未定义的行为,因为b不是Derived类型。未定义的行为意味着一切都会发生,包括按预期工作的程序。更改设置可以产生不同的"未定义行为",这就是您可以观察到的。