我正在研究用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;
}
现在,我已经定义了从int
到wrapper
的转换构造函数以及从类类型到int
的转换运算符(我还重载了&lt;&lt;输出运算符为了打印一些结果),但是当编译器评估表达式w1+1
时,似乎没问题。怎么可能是??
答案 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选择语句)
- ...作为表达式的条件的值是的值 表达式,上下文转换为bool以用于其他语句 比开关;
醇>
和(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
。但是,int
到class_type
会隐式发生,除非您制作class_type
的构造函数explicit
:
explicit ABC(int x) : v(x) { }
如果您可以访问C ++ 11,那么您还可以明确转换功能:
explicit operator int() const { return v; }