簡體   English   中英

為什么虛擬功能會中斷我的工作?

[英]Why does a virtual function break my casting?

我正在努力擴展以下代碼:

#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和虛擬析構函數使類具有多態性。 我還嘗試實現從Base到Derived的顯式下垂構造函數,但我失敗了。

PS:不能更改'Base'。

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 未定義的行為意味着一切都可能發生,包括程序按預期工作。 稍微更改設置會產生不同的“不確定行為”,這就是您可以觀察到的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM