选择性隐式转换

时间:2014-03-22 23:56:44

标签: c++ implicit-conversion ostream

我有一个Value类,它可以保存各种数据类型的值。

class Value
{
    private:
        union
        {
            int Integer;
            double Real;
            bool Boolean;
        };

        ValueTypes valType;

    public:
        Value();
        Value(double Val);
        Value(int Val);
        Value(bool Val);

        /* ... */

        friend std::ostream& operator <<(std::ostream& stream, const Value& val);
}

我想重载<<运算符,因此可以打印一个值,而无需调查其类型。

这是我目前的实施:

std::ostream &operator <<(std::ostream &os, const Value &val)
{
    switch (val.valType)
    {
        case ValueTypes::Real:
            os << val.Real;
            break;

        case ValueTypes::Integer:
            os << val.Integer;
            break;

        case ValueTypes::Boolean:
            os << (val.Boolean ? "True" : "False");
            break;
    }

    return os;
}

首先,在使用g ++(CodeBlocks IDE,Ubuntu)进行编译时,实现会导致隐式转换为Value。当值类型为IntegerReal时,os <<语句会将其转换为Value,然后再次调用ostream重载(无限)递归),所以我最终得到了分段错误。

其次,在使用Visual C ++进行编译时,隐式转换已经消失,并且它打印的值很好(不会调用隐式构造函数)。

注意:

我希望保持隐式构造函数,因为它增强了可读性并简化了项目其他部分的维护。

此外,我发现了以下blog post,但未能调整我的代码,因此它将按照我的意愿执行(模板的使用有点超出了我目前对cpp语法的理解)。

如何在特定的ostream重载功能中禁用隐式转换?

修改 启用-Wall后,我在CodeBlocks中没有收到任何警告。

1 个答案:

答案 0 :(得分:3)

您需要#include <ostream>。没有它的原因是它没有用,因为那是实际定义std::ostream的标题和所有有用的operator<<函数。

它没有吓到并抱怨“std::ostream”(或其他<<运营商)没有定义的原因是因为前向声明。如果转发声明类型,则可以将其用作指针或引用(只要您不尝试进一步访问它)。 You can do some things with an incomplete type

您包含的其他标题可能会向前声明std::ostream,但永远不会为它和所有<<运算符提供完整的定义。至少在你的Ubuntu系统上。在其他系统上,其他标头可能包含<ostream>或至少提供了<ostream>所做的一些定义。您的operator<<可能是编译器看到的唯一一个(因为您没有包含<ostream>),并且因为它是编译器唯一知道的,所以它试图将它用于所有内容。

简而言之,在处理跨平台的东西时,人们应该迂腐地确定必要的内容(而不是依赖其他标题来包含与它们无关的内容)。