为什么虚函数会破坏我的转换?
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
中并使它们成为 virtual/abstract,以便 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
类型。未定义的行为意味着一切都可能发生,包括程序按预期工作。稍微更改设置可以产生不同的 "undefined behaviour",这就是您可以观察到的结果。
我正在努力扩展以下代码:
#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
中并使它们成为 virtual/abstract,以便 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
类型。未定义的行为意味着一切都可能发生,包括程序按预期工作。稍微更改设置可以产生不同的 "undefined behaviour",这就是您可以观察到的结果。