所以我在 C++ 中有一个虚拟流接口
class KxStream
{
public:
virtual KxStream& operator<< ( u32 num ) = 0;
};
它有大量适用于所有内置类型的基本 << 运算符。我刚刚列出了一个。
然后我有一些实现流接口的类。像这样:
class KxCbuf : public KxStream
{
public:
KxStream& operator<<( u32 num );
}
所以在 KxCbuf 中有一个流接口的实现。到目前为止,一切都很好。然后我有一些重载流接口的类:
class KxSymbol
{
operator u32() const;
friend KxStream& operator<<( KxStream& os, KxSymbol sym );
};
请注意,此类已将运算符强制转换为内置类型。现在,当我尝试将这些类之一流式传输到实现流式接口的类之一时,我收到一个错误:
KxCbuf buf;
KxSymbol sym;
buf << sym; // error!
编译器对使用哪些函数感到困惑。Gcc 编译得很好,但是说有多种方法可以做到这一点。MSVC 没有编译说有多个重载:
src/variable.cpp(524) : error C2666: 'KxCbuf::operator <<' : 15 overloads have similar conversions
我知道发生了什么,只是不知道如何令人满意地解决它。所以编译器可以要么强制转换 KxCbuf -> KxStream,然后调用友元函数,这是正确的做法。或者它可以强制转换 KxSymbol -> u32,然后调用继承自 KxStream 的 KxCbuf 中的 u32 << 运算符。
我可以用两种(坏的)方法解决它。
我可以从流式传输一些明确的内容开始:
buf << "" << sym;
这样第一个流运算符“”的返回值返回KxStream,一切正常。或者我可以为实现类实现一个冗余的流操作符。例如,我可以将以下内容添加到 KxSymbol:
friend KxStream& operator<<( KxCbuf& os, KxSymbol sym );
第一个答案总是有效的 - 但它肯定是丑陋的。第二个答案也很丑陋,因为我必须创建冗余的流运算符,并且并不总是有效,因为 KxStream 实现在我需要定义新的流运算符的地方并不总是可见。
理想情况下,我希望 KxStream 接口的实现就像 KxStream 对象一样工作,并避免导致模糊转换的隐式转换。
我该如何解决这个问题?
(ps。我需要为我的库的自定义序列化方案创建自己的流操作符。我不能使用具有自己的序列化类的 boost 或类似的第三方库)
@Edit:有几个很好的答案与控制编译器对隐式转换的使用有关,比如转换为 KxSymbol -> u32,不幸的是隐式转换对代码很重要。例如,KxSymbol 是一个将字符串存储在表格中并将它们作为数字返回的类,以便我可以将字符串作为数字进行比较。例如,如果两个符号不相等,则字符串不相同。我还将符号作为数字存储在某些数据结构中。
有没有办法从另一边解决这个问题,以某种方式让编译器理解 KxStream 的实现应该优先于其他隐式转换转换为 KxStream 对象?
例如,如果我以某种方式强制编译器必须首先将 KxCbuf 转换为 KxStream,然后再使用 operator<< 来处理内置类型。这将使它总是更喜欢重载运算符<<'而不是 KxStream 运算符。- 重载需要一次,而 KxStream 需要两次。