C++ 重载转换运算符

Posted

技术标签:

【中文标题】C++ 重载转换运算符【英文标题】:C++ Overloading Conversion Operators 【发布时间】: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 的公共方法会更好吗?

【问题讨论】:

【参考方案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

【讨论】:

以上是关于C++ 重载转换运算符的主要内容,如果未能解决你的问题,请参考以下文章

C++ 强制转换运算符重载和多态性

操作重载与类型转换C++

操作重载与类型转换C++

操作重载与类型转换C++

重载强制转换运算符时的 C++ 歧义

c++ 转换运算符重载、枚举、整数和字符