【问题标题】:C++ Overloading Conversion OperatorsC++ 重载转换运算符
【发布时间】:2012-04-23 13:19:42
【问题描述】:

我正在尝试创建一个允许隐式转换为某些内置类型的类,例如 unsigned long int 并且因为我试图尽可能正确地执行此操作(这是我在 C++ 中的第一个重要项目),所以我有遇到一个关于 const 正确性的奇怪问题:

这行得通:

#include <iostream>

class CustomizedInt
{
private:
    int data;
public:
    CustomizedInt();
    CustomizedInt(int input);
    operator unsigned long int () const
    {
        unsigned long int output;
        output = (unsigned long int)data;
        return output;
    }
};

CustomizedInt::CustomizedInt()
{
    this->data = 0;
}

CustomizedInt::CustomizedInt(int input)
{
    this->data = input;
}

int main()
{
    CustomizedInt x;
    unsigned long int y = x;

    std::cout << y << std::endl;

    return 0;
}

但是这个:

#include <iostream>

class CustomizedInt
{
private:
    int data;
public:
    CustomizedInt();
    CustomizedInt(int input);
    operator unsigned long int () const;
};

CustomizedInt::CustomizedInt()
{
    this->data = 0;
}

CustomizedInt::CustomizedInt(int input)
{
    this->data = input;
}

CustomizedInt::operator unsigned long()
{
    unsigned long int output;
    output = (unsigned long int)data;
    return output;
}

int main()
{
    CustomizedInt x;
    unsigned long int y = x;

    std::cout << y << std::endl;

    return 0;
}

在 Visual Studio 2010 中给我这个错误:error C2511: 'CustomizedInt::operator unsigned long(void)' : overloaded member function not found in 'CustomizedInt'

现在,如果我从运算符定义中删除关键字 const,一切正常。这是一个错误吗?我读到我应该在每个(公共)方法/运算符之后使用 const 关键字,以便清楚地表明它不会以任何方式改变当前对象。

另外,我知道定义这样的运算符可能是不好的做法,但我不确定我是否完全理解相关的注意事项。有人可以概述一下吗?只定义一个名为 ToUnsignedLongInt 的公共方法会更好吗?

【问题讨论】:

    标签: c++ operator-overloading const-correctness


    【解决方案1】:

    函数签名与函数定义不匹配。

    operator unsigned long int () const;
    

    CustomizedInt::operator unsigned long()    { ... }
                                           ^^^
                                       const missing
    

    在这种情况下,您应该将转换运算符标记为const,因为它不会影响对象的内部状态。

    另外,使用构造函数初始化列表来初始化你的成员变量。

    CustomizedInt::CustomizedInt()
    : data()
    {
    }
    
    CustomizedInt::CustomizedInt(int input)
    : data(input)
    {
    }
    

    【讨论】:

    • 好的,谢谢!出于某种原因,我认为我不需要在实现中重复后置的 const ......关于构造函数,是的,初始化列表很有用,但是,在我的实际实现中,数据具有复杂类型,并且构造函数初始化列表的实现有点过于复杂...
    • @MihaiTodor 如果data 有一个复杂的类型,我会说这是使用初始化列表而不是赋值的更多理由。 C++ FAQ 解释了为什么这是一种好的做法,并列出了该规则的一些例外情况。
    • 好吧,我完全同意,但是如果您需要调用某些函数来初始化该数据,您会怎么做?我正在使用 GMP 库,数据类型为 mpz_t,需要使用 mpz_init(...) 进行初始化。如何对初始化列表中的数据调用 mpz_init 函数?
    • @MihaiTodor 在这种情况下你不能;这就是我们为使用 C 库付出的代价 :-)
    • 是的,同意 :) 无论如何,在我完成这个项目后,我希望我会对 C++ 感到更舒服,因为我的背景主要是脚本语言和 C#,所以我接受它慢慢来。
    【解决方案2】:

    可以从声明中删除const,但您几乎可以肯定想要做的是添加它到定义中:

    CustomizedInt::operator unsigned long() const
    {
        unsigned long int output;
        output = (unsigned long int)data;
        return output;
    }
    

    【讨论】:

    • 好吧,但是如果这个操作符的实现比我的简单例子大呢?不想在header中添加10行实现代码,所以想在类外实现...
    • @michael85:保持标题不变。只需在您实现它的地方添加const。两个签名需要匹配。
    【解决方案3】:

    是的,如果您的成员函数不影响对象的逻辑状态,那么您确实应该使用const 对其进行后缀,以便编译器强制执行。

    但是这种情况下,还需要在定义函数体的时候加上const

    【讨论】:

      【解决方案4】:

      您只需将相同的函数原型复制到实现中。 即。

      CustomizedInt::operator unsigned long int() const
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-22
        • 1970-01-01
        • 2010-12-09
        • 1970-01-01
        • 1970-01-01
        • 2015-03-29
        • 2014-08-18
        • 1970-01-01
        相关资源
        最近更新 更多