与类类型之间的隐式转换
我正在研究 C++ 中的转换构造函数和转换运算符.到目前为止,我学到的是,任何只接受一个参数(以及任意数量的可选默认参数)的非显式构造函数都表示隐式类类型转换为 THAT 类类型,例如,如果一个类定义了一个具有int
类型的一个参数我可以在需要该类类型的对象的任何地方使用 int
:
(假设 class_type 有一个重载的 += 运算符)
class_type a;a+=5;
在这种情况下,5 被隐式转换(通过转换构造函数)为 class_type
,并调用重载运算符.
现在,(至少对我而言)棘手的部分:我知道我可以将转换运算符定义为成员函数:
运算符 int() {....};
将 class_type
的对象转换为原始 int
类型,我可以像这样使用该转换:
class_type a;一个+5;
在这种情况下,我读到该对象通过其转换运算符转换为 int,然后调用内置求和运算符.但是,如果我定义了一个重载的 + 运算符以将两个 class_type 对象作为其参数呢?像
class_type operator+(const class_type&,const class_type &c);
编译器应该如何知道通过函数匹配调用哪一个?int
的转换是否仅在仅定义内置运算符时隐式发生?
谢谢!
实际上,我已经尝试编写一些代码来有效地尝试一下,结果我的编译器 (g++) 没有发出任何模棱两可的调用错误!
这是类头(连同非成员操作符+函数声明):
#include <iostream>类包装{朋友 std::ostream &operator<<(std::ostream&,const wrapper&);上市:包装器()=默认;包装器(int);整数获取();运算符 int() 常量;包装运算符+(int);私人的:诠释a = 10;};std::ostream &operator<<(std::ostream&,const wrapper&);
这是主要代码:
#include "wrapper.h"主函数(){使用命名空间标准;包装 w1;包装 w2(5);cout<
现在,我已经定义了一个从 int
到 wrapper
的转换构造函数和一个从类类型到 int
的转换运算符(我已经还重载了 << 输出运算符以打印一些结果),但是当编译器评估表达式 w1+1
时,它似乎没问题.怎么可能?
如果你有例如以下包含转换构造函数和转换运算符的类声明
结构 A{A( 整数 x ) : x( x ) {}运算符 int() const { 返回 x;}诠释 x;};const A 运算符 +( const A &a1, const A &a2 ){返回 A(a1.x + a2.x);}
那么语句
a1 + a2;
其中 a1 和 a2 被声明为例如
A a1( 10 );一个 a2( 20 );
将是格式良好的,因为不需要调用转换函数.两个操作数都匹配运算符 + 的参数声明.
但是如果你会写例子
a1 + 20;
当编译器因为存在歧义而发出错误时.编译器可以应用转换构造函数 A( int )
将第二个操作数转换为 A
类型,并调用为 A
类型的对象定义的运算符.或者它可以应用转换运算符 operator int
将第一个操作数转换为类型 int
并调用内置的 operator +
类型的对象int
.
为避免这种歧义,您可以使用函数说明符 explicit
声明构造函数或运算符(或两者).
例如
显式 A( int x ) : x( x ) {}
或
显式运算符 int() const { return x;}
在这种情况下,只有一个隐式转换存在并且没有歧义.
我想附加上面的描述,有时某些转换运算符可以被隐式调用,即使它们是用函数说明符explicit
声明的.
例如根据 C++ 标准(6.4 选择语句)
<块引用>- ...作为表达式的条件的值是表达式,上下文转换为布尔语句其他比切换;
和(5.16 条件运算符)
<块引用>1 条件表达式从右到左分组.第一个表达式是上下文转换为 bool(第 4 条).
例如,如果上面的类具有使用函数说明符 explicit
显式运算符 bool() const { return x != 0;}
但是它会被隐式调用,例如在下面的语句中
A a( 10 );std::cout <<(a ? "true" : "false" ) <<标准::endl;
这里 a 将在条件运算符中转换为 bool 类型的对象.
在你更新你的问题这个表达之后
w1+1;
与运算符完全匹配
包装运算符+(int);
不需要转换.所以代码编译成功.
I am studying converting constructors and conversion operators in C++.
What I've learned so far is that any non-explicit constructor that takes only one parameter (and any number of optional default arguments) represents an implicit class-type conversion to THAT class type, for example if a class defines a constructor that has one parameter of type int
I can use an int
wherever an object of that class type is required:
(assuming class_type has an overloaded += operator)
class_type a;
a+=5;
in this case 5 is implicitly converted (through the converting constructor) to class_type
and the overloaded operator is called.
Now, the (at least for me) tricky part: I know I can define a conversion operator as a member function :
operator int() {....};
that converts the object of class_type
to the primitive int
type, and I can use that conversion like:
class_type a;
a+5;
in this case I've read that the object is converted to an int through its conversion operator and then the buil-in sum operator is called. But what if I defined an overloaded + operator to take two class_type objects as its arguments? something like
class_type operator+(const class_type&,const class_type &c);
how is the compiler supposed to know which one to call through function matching?
does the conversion to int
only happens implicitly when only the built-in operator is defined?
thanks!
edit:
actually,I've tried to write some code to effectively try it out, it turned out that my compiler (g++) doesn't issue any ambiguous call error!
this is the class header (along with the non-memeber operator+ function declaration) :
#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&);
and this is the main code:
#include "wrapper.h"
int main()
{
using namespace std;
wrapper w1;
wrapper w2(5);
cout<<w1<<" "<<w2<<endl;
w1+1;
}
now,I've defined a converting constructor from int
to wrapper
AND a conversion operator from class type to int
(I've also overloaded the << output operator in order to print some results), but when the compiler evaluates the expression w1+1
it seems to be fine. How could it possibly be??
If you have for example the following class declaration that contains a conversion constructor and a conversion operator
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 );
}
then statement
a1 + a2;
where a1 and a2 are declared like for example
A a1( 10 );
A a2( 20 );
will be well-formed because there is no need to call a conversion function. The both operands match the parameter declarations of the operator +.
However if you will write for example
a1 + 20;
when the compiler issues an error because there is an ambiguity. The compiler can either apply conversion constructor A( int )
to convert the second operand to type A
and call the operator defined for objects of type A
. Or it can apply the conversion operator operator int
to convert the first operand to type int
and call the built-in operator +
for objects of type int
.
To avoid this ambiguity you could declare either the constructor or the operator (or the both) with function specifier explicit
.
For example
explicit A( int x ) : x( x ) {}
or
explicit operator int() const { return x; }
In this case only one implicit conversion would exist and there was not an ambigiuty.
I would like to append the above description that sometimes some converion operators can be called implicitly even if they are declared with the function specifier explicit
.
For example According to the C++ Standard (6.4 Selection statements)
- ...The value of a condition that is an expression is the value of the expression, contextually converted to bool for statements other than switch;
and (5.16 Conditional operator)
1 Conditional expressions group right-to-left. The first expression is contextually converted to bool (Clause 4).
So for example if the above class has the following conversion operator declared with the function specifier explicit
explicit operator bool() const { return x != 0; }
nevertheless it will be called implicitly for example in the following statement
A a( 10 );
std::cout << ( a ? "true" : "false" ) << std::endl;
Here a will be converted to an object of type bool in the conditional operator.
EDIT: After you updated your question this expression
w1+1;
is an exact match for operator
wrapper operator+(int);
Neither conversion are required. So the code compiles successfully.
相关文章