所以我在c ++中有一个虚拟流媒体接口
class KxStream
{
public:
virtual KxStream& operator<< ( u32 num ) = 0;
};
它有一吨基本&lt;&lt;所有内置类型的运算符。我刚刚列出了一个。
然后我有一些实现流接口的类。像这样:
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 - &gt; KxStream,然后调用友元函数,这是正确的事情。或者它可以投射KxSymbol - &gt; u32,然后调用u32&lt;&lt; KxCbuf中的运算符,继承自KxStream。
我可以解决两种(不好的)方式。
我可以从明确的流式传输开始:
buf << "" << sym;
这样,“”返回KxStream的第一个流操作符的返回值,一切都很好。或者我可以为实现类实现冗余流操作符。例如。我可以将以下内容添加到KxSymbol:
friend KxStream& operator<<( KxCbuf& os, KxSymbol sym );
第一个答案总是有效 - 但肯定是丑陋的。第二个答案也是丑陋的,因为我必须创建冗余流操作符,并不总是这样,因为KxStream实现在我需要定义新流操作符的地方并不总是可见。
理想情况下,我希望KxStream接口的实现与KxStream对象一样工作,并避免导致模糊转换的隐式转换。
我该如何解决这个问题?
(ps。我需要为我的库创建自己的流式操作符,用于自定义序列化方案。我不能使用具有自己的序列化类的boost或类似的第三方库)
@Edit:有几个很好的答案与控制编译器使用隐式转换有关,比如转换为KxSymbol - &gt; u32,遗憾的是隐式转换对代码很重要。例如,KxSymbol是一个在表中存储字符串并将它们作为数字返回的类,以便我可以将字符串作为数字进行比较。例如。如果两个符号不相等,则字符串不相同。我还将符号存储为某些数据结构中的数字。
有没有办法从对方解决这个问题,的某种方式使编译器明白KxStream的实现应该优先被强制转换为KxStream对象与其它隐式转换?的
例如,如果我以某种方式迫使编译器在使用运算符&lt;&lt;之前必须先将KxCbuf强制转换为KxStream,该怎么办?对于内置类型。这将使它总是更喜欢过载运算符&lt;&lt;&gt;而不是KxStream运算符。 - 重载需要一次转换,而KxStream则需要两次。
答案 0 :(得分:5)
如果您有C ++ 11编译器,请将转换函数标记为“explicit”。这样你就不会对u32进行隐式转换,这种模糊性就会消失。
答案 1 :(得分:3)
最简单,最安全的方法是将隐式转换从operator u32() const;
更改为命名方法u32 as_u32() const
。这不仅消除了它可以防止将来让你陷入麻烦的各种意外转换的模糊性。
答案 2 :(得分:0)
我想我可能有答案。在虚拟私有方法中实现内置流操作符。
所以我这样做:
class KxStream
{
public:
KxStream& operator<< ( u32 num ) { return stream_i( num ); }
private:
virtual KxStream& stream_i ( u32 num ) = 0;
};
class KxCbuf : public KxStream
{
private:
KxStream& stream_i( u32 num );
}
现在编译器无法调用内置运算符&lt;&lt;通过KxCbuf。它只能使用KxStream中的公共方法。但我仍然通过私有stream_i方法获取虚方法重载。因此,当流式传输到KxCbuf时,编译器必须始终强制转换为KxStream。这是唯一的方法。
当在朋友重载和内置插件之间做出决定时,朋友重载获胜,因为内置插件需要2个强制转换并且重载需要一个。