从类类型

时间:2015-08-18 09:07:38

标签: c++ c++11 type-conversion

我正在研究用C ++转换构造函数和转换运算符。 到目前为止我学到的是,任何只带一个参数(以及任意数量的可选默认参数)的非显式构造函数表示对THAT类类型的隐式类类型转换,例如,如果类定义了一个构造函数, int类型的一个参数只要需要该类类型的对象,我就可以使用int

(假设class_type有一个重载的+ =运算符)

class_type a;
a+=5;

在这种情况下,5被隐式转换(通过转换构造函数)到class_type,并调用重载的运算符。

现在,(至少对我来说)棘手的部分:我知道我可以将转换运算符定义为成员函数:

operator int() {....};

class_type的对象转换为原始int类型,我可以使用以下转换:

class_type a;
a+5;

在这种情况下,我已经读过通过转换运算符将对象转换为int,然后调用内置和运算符。 但是如果我定义了一个重载的+运算符来将两个class_type对象作为其参数呢?

之类的东西

class_type operator+(const class_type&,const class_type &c);

编译器如何知道通过函数匹配调用哪一个? 转换为int只会在仅定义内置运算符时隐式发生吗?

谢谢!

编辑:

实际上,我已经尝试编写一些代码来有效地尝试它,结果发现我的编译器(g ++)没有发出任何模糊的调用错误!

这是类标题(以及非memeber运算符+函数声明):

#include <iostream>

class wrapper {
    friend std::ostream &operator<<(std::ostream&,const wrapper&);
  public:
    wrapper()=default; 
    wrapper(int);
    int get();
    operator int() const;
    wrapper operator+(int);
  private:
    int a=10;
};

std::ostream &operator<<(std::ostream&,const wrapper&);

这是主要代码:

#include "wrapper.h"

int main()
{
  using namespace std;
  wrapper w1;
  wrapper w2(5);
  cout<<w1<<" "<<w2<<endl;
  w1+1;  
}

现在,我已经定义了从intwrapper的转换构造函数以及从类类型到int的转换运算符(我还重载了&lt;&lt;输出运算符为了打印一些结果),但是当编译器评估表达式w1+1时,似乎没问题。怎么可能是??

2 个答案:

答案 0 :(得分:15)

如果您有以下类声明,其中包含转换构造函数和转换运算符

struct A
{
    A( int x ) : x( x ) {}
    operator int() const { return x; }
    int x;
};        

const A operator +( const A &a1, const A &a2 )
{
    return A( a1.x + a2.x );
}

然后声明

a1 + a2;

其中a1和a2被声明为例如

A a1( 10 );
A a2( 20 );

格式正确,因为无需调用转换函数。这两个操作数与operator +的参数声明匹配。

但是,如果您要编写例如

a1 + 20;

当编译器发出错误时,因为存在歧义。编译器可以应用转换构造函数A( int )将第二个操作数转换为类型A,并调用为A类型的对象定义的运算符。或者,它可以应用转化运算符operator int将第一个操作数转换为int类型,并为类型为operator +的对象调用内置int

为避免这种歧义,您可以使用函数说明符explicit声明构造函数或运算符(或两者)。

例如

    explicit A( int x ) : x( x ) {}

    explicit operator int() const { return x; }

在这种情况下,只存在一个隐式转换,并且没有任何限制。

我想附加上面的描述,即使用函数说明符explicit声明它们,有时也可以隐式调用某些转换运算符。

例如根据C ++标准(6.4选择语句)

  
      
  1. ...作为表达式的条件的值是的值   表达式,上下文转换为bool以用于其他语句   比开关;
  2.   

和(5.16条件运算符)

  

1条件表达式从右到左分组。第一个表达是   在语境上转换为布尔(第4条)。

例如,如果上面的类具有使用函数说明符explicit声明的以下转换运算符

explicit operator bool() const { return x != 0; }

然而,它将被隐式调用,例如在以下声明中

A a( 10 );

std::cout << ( a ? "true" : "false" ) << std::endl;

这里a将在条件运算符中转换为bool类型的对象。

编辑:更新您的问题后,此表达式

w1+1; 

与运营商完全匹配

wrapper operator+(int);

不需要转换。所以代码编译成功。

答案 1 :(得分:3)

您可以轻松地尝试查看编译器的功能:

#include <iostream>

struct ABC {
    int v;
    ABC(int x) : v(x) { }
    operator int() const { return v; }
    void operator +=(ABC const &that) {
        v += that.v;
    }
};

ABC operator+(ABC const &lhs, ABC const &rhs) {
    return { lhs.v + rhs.v };
}

int main() {
    ABC a(5);
    std::cout << a + 1 << '\n';
    a += 10;
    std::cout << a << '\n';
}
  

如果我定义了一个重载的+运算符来将两个class_type对象作为其参数?

GCC

  

错误:&#39;运营商+&#39;模糊过载(操作数类型是&#39; ABC&#39;和&#39; int&#39;)

编译器会看到两个候选人:operator+(int, int) <built-in>ABC operator+(const ABC&, const ABC&)。这意味着它不仅可以隐式地将5中的a + 5转换为a,还可以将a隐式转换为int。发布这些转化后,operator+个功能都会成为潜在匹配。

  

编译器如何知道通过函数匹配调用哪一个?

因此不知道错误。

  

只有在定义了内置运算符时才会隐式转换为int吗?

是的,否则它不会自动将class_type转换为int。但是,intclass_type会隐式发生,除非您制作class_type的构造函数explicit

explicit ABC(int x) : v(x) { }

如果您可以访问C ++ 11,那么您还可以明确转换功能:

explicit operator int() const { return v; }