转换运算符在 C++ 中如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1307876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do conversion operators work in C++?
提问by AraK
Consider this simple example:
考虑这个简单的例子:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
转换运算符在 C++ 中如何工作?(即)编译器何时尝试替换转换运算符之后定义的类型?
回答by Johannes Schaub - litb
Some random situations where conversion functions are used and not used follow.
使用和不使用转换函数的一些随机情况如下。
First, note that conversion functions are never used to convert to the same class type or to a base class type.
首先,请注意,从不使用转换函数来转换为相同的类类型或基类类型。
Conversion during argument passing
参数传递期间的转换
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
参数传递期间的转换将使用复制初始化规则。这些规则只考虑任何转换函数,不考虑是否转换为引用。
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
参数传递只是复制初始化的一种上下文。另一种是使用复制初始化语法的“纯”形式
B b = A(); // called!
Conversion to reference
转换为参考
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
在条件运算符中,如果转换为左值的类型,则可以转换为引用类型。
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
另一个引用的转换是当你绑定一个引用时,直接
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
转换为函数指针
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
您可能有一个到函数指针或引用的转换函数,并且在进行调用时可能会使用它。
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
这东西有时实际上会变得非常有用。
Conversion to non class types
转换为非类类型
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
无处不在的隐式转换也可以使用用户定义的转换。您可以定义一个返回布尔值的转换函数
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
(在这种情况下,转换为 bool 可以通过safe-bool idiom变得更安全,以禁止转换为其他整数类型。)在内置运算符需要特定类型的任何地方触发转换。不过,转换可能会成为障碍。
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t
needs be different from int
then).
调用可能不明确,因为对于成员,第二个参数需要转换,而对于内置运算符,第一个需要用户定义的转换。其他两个参数分别完美匹配。在某些情况下,调用可以是明确的(ptrdiff_t
需要与int
那时不同)。
Conversion function template
转换函数模板
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
模板允许一些好的东西,但最好对它们非常谨慎。以下使类型可转换为任何指针类型(成员指针不被视为“指针类型”)。
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
回答by AraK
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
这 ”。” 运算符在 C++ 中不可重载。每当您说 xy 时,不会自动对 x 执行任何转换。
回答by Tyler McHenry
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
转换不是魔术。仅仅因为 A 有一个到 B 的转换并且 B 有一个 foo 方法并不意味着 a.foo() 会调用 B::foo()。
The compiler tries to use a conversion in four situations
编译器尝试在四种情况下使用转换
- You explicitly cast a variable to another type
- You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
- You assign the variable to a variable of a different type
- You use the variable copy-construct or initialize a variable of a different type
- 您显式地将变量转换为另一种类型
- 您将变量作为参数传递给在该位置需要不同类型的函数(运算符在这里算作函数)
- 您将变量分配给不同类型的变量
- 您使用变量复制构造或初始化不同类型的变量
There are three types of conversions, other than those involved with inheritance
除了涉及继承的转换,还有三种类型的转换
- Built-in conversions (e.g. int-to-double)
- Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
- User-defined conversion operators, where class A defines an operator B (as in your example)
- 内置转换(例如 int-to-double)
- 隐式构造,其中 B 类定义了一个构造函数,该构造函数采用类型 A 的单个参数,并且不使用“explicit”关键字对其进行标记
- 用户定义的转换运算符,其中类 A 定义运算符 B(如您的示例)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standarddiscusses implicit construction and user-defined conversion operators.
编译器如何决定使用哪种类型的转换以及何时(尤其是当有多种选择时)非常复杂,我会尝试将其压缩为 SO 的答案。C++ 标准的第 12.3 节讨论了隐式构造和用户定义的转换运算符。
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
(可能有一些我没有想到的转换情况或方法,如有遗漏请评论或编辑)
回答by Steve Jessop
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
将参数传递给函数(包括类的重载和默认运算符)时会发生隐式转换(无论是通过转换运算符还是非显式构造函数)。除此之外,还有一些对算术类型执行的隐式转换(因此添加一个 char 和一个 long 导致两个 long 相加,得到一个 long 结果)。
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
隐式转换不适用于对其进行成员函数调用的对象:对于隐式转换而言,“this”不是函数参数。
回答by C?t?lin Piti?
You should do
你应该做
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
编译器没有自动转换为 person 的信息,因此您需要显式转换。
If you would use something like
如果你会使用类似的东西
person pers = p;
Then the compiler has information for implicit casting to person.
然后编译器具有用于隐式转换为 person 的信息。
You can have "casting" through constructors:
您可以通过构造函数进行“转换”:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
这些是一些简短的例子。转换(隐式、显式等)需要更多解释。您可以在严肃的 C++ 书籍中找到详细信息(请参阅有关堆栈溢出的 C++ 书籍的问题以获得好的标题,例如这本)。
回答by sbi
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T
where U
is required.
如果您尝试使用类型的对象(参考)编译器将尝试一个(!),用户自定义投(隐式构造函数或转换运算符)T
这里U
是必需的。
The .
operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->()
can be overloaded for.
该.
运营商,但是,总是会尝试在其左侧访问的对象(参考)的成员。这只是它的定义方式。如果你想要更花哨的东西,那就是operator->()
可以超载的。
回答by MAB
//Virtual table Fuction(VFT)
//虚拟表功能(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}