简体   繁体   English

C ++中的转换运算符

[英]Conversion Operators in C++

Please help me understand how exactly the conversion operators in C++ work. 请帮助我理解C ++中转换运算符的确切运作方式。 I have a simple example here which I am trying to understand, though it is not very clear how the conversion actually happens by the compiler. 我在这里有一个简单的例子,我试图理解,虽然目前还不是很清楚编译器实际上是如何进行转换的。

class Example{
public:
    Example();
    Example(int val);
    operator unsigned int();
    ~Example(){}
private:
    int itsVal;
};

Example::Example():itsVal(0){}

Example::Example(int val):itsVal(val){}

Example::operator unsigned int (){
    return (itsVal);
}

int main(){
    int theInt = 5;
    Example exObject = theInt; // here 
    Example ctr(5);
    int theInt1 = ctr; // here
    return 0;
}

You can walk through that code with a debugger (and/or put a breakpoint on each of your constructors and operators) to see which of your constructors and operators is being invoked by which lines. 您可以使用调试器(和/或在每个构造函数和运算符上放置断点)来遍历该代码,以查看哪些构造函数和运算符由哪些行调用。

Because you didn't define them explicitly, the compiler also created a hidden/default copy constructor and assignment operator for your class. 因为您没有显式定义它们,所以编译器还为您的类创建了一个隐藏/默认的复制构造函数和赋值运算符。 You can define these explicitly (as follows) if you want to use a debugger to see where/when they are being called. 如果要使用调试器来查看调用它们的位置/时间,可以显式定义这些(如下所示)。

Example::Example(const Example& rhs)
: itsVal(rhs.itsVal)
{}

Example& operator=(const Example& rhs)
{
    if (this != &rhs)
    {
        this->itsVal = rhs.itsVal;
    }
    return *this;
}
int main() {
    int theInt = 5;

    /**
     * Constructor "Example(int val)" in effect at the statement below.
     * Same as "Example exObject(theInt);" or "Example exObject = Example(theInt);"
     */
    Example exObject = theInt; // 1

    Example ctr(5);

    /**
     * "operator unsigned int()" in effect at the statement below.
     * What gets assigned is the value returned by "operator unsigned int()".
     */
    int theInt1 = ctr; // 2

    return 0;
}

At statement 1 the constructor Example(int val) is called. 在语句1处,调用构造函数Example(int val) Declare it as explicit Example(int val) and you will get a compile time error ie no implicit conversion will then be allowed for this constructor. 将其声明为explicit Example(int val) ,您将得到编译时错误,即此构造函数不允许隐式转换。

All single argument constructors are called implicitly if the assigned value is of their respective argument type. 如果指定的值是它们各自的参数类型,则隐式调用所有单个参数构造函数。 Using the explicit keyword before single argument constructors disables implicit constructor calling and hence implicit conversion. 在单个参数构造函数之前使用explicit关键字会禁用隐式构造函数调用,从而禁用隐式转换。

If the constructor was declared as explicit ie explicit Example(int val) then the following would happen for each statement. 如果构造函数声明为显式,即explicit Example(int val)则每个语句都会发生以下情况。

Example exObject(theInt); // Compile time error.
Example exObject = theInt; // Compile time error.
Example exObject(Example(theInt)); // Okay!
Example exObject = Example(theInt); // Okay!

Also note that in case of implicit constructor call and hence implicit conversion the assigned value is an rvalue ie an un-named object implicitly created using an lvalue (theInt) which tells us that in case of implicit conversion the compiler converts 还要注意,在隐式构造函数调用和隐式转换的情况下,赋值是rvalue,即使用左值(theInt)隐式创建的未命名对象,它告诉我们在隐式转换的情况下编译器转换

Example exObject = theInt;

to

Example exObject = Example(theInt);

So (in C++11) don't expect the lvalue constructor to be called seeing that you are using an lvalue ie a named value theInt for assignment. 因此(在C ++ 11中)不要指望调用左值构造函数,因为您正在使用左值,即用于赋值的命名值theInt What gets called is the rvalue constructor since the assigned value is actually the un-named object created using the lvalue. 被调用的是rvalue构造函数,因为赋值的实际上是使用左值创建的未命名对象。 However, this applies if you have both lvalue and rvalue versions of the constructor. 但是,如果您同时具有构造函数的左值和右值,则适用。

At statement 2 operator unsigned int() is called. 在语句2处调用operator unsigned int() Simply consider it as a normal function call with a weird name and the fact that it can get called automagically when an implicit conversion happens. 简单地将它视为具有奇怪名称的普通函数调用,以及当隐式转换发生时它可以自动调用的事实。 The value returned by that function is the value assigned in the expression. 该函数返回的值是表达式中指定的值。 And since in you implementation the value returned is an int it correctly gets assigned to int theInt1 . 并且因为在您实现中返回的值是一个int,它正确地分配给int theInt1

To be precise operator unsigned int() overloads () operator which is the cast operator. 准确地说, operator unsigned int() overloads ()运算符是转换运算符。 In your case it's overloaded for int hence whenever an object of Example class is assigned to an int the implicit type casting from Example to int takes place and hence operator unsigned int() gets called. 在您的情况下,它重载int因此每当的目的Example类被分配给一个int从隐式类型铸造Exampleint发生,并因此operator unsigned int()被调用。 Therefore, 因此,

int theInt1 = ctr;

is equivalent to 相当于

int theInt1 = (int)ctr;
Example exObject = theInt; // implicitly created copy constructor takes place
// object implicitly created from int and then copied
// it is like
Example exObject = Example(theInt);
// so it uses sequence
// Example(int) -> Example(const Example&)
int theInt1 = ctr; // operator int()

If you compiler supports copy constructor optimization and return value optimization you won't notice 如果您的编译器支持复制构造函数优化和返回值优化,您将不会注意到

Example(const Example&)

execution, but you can declare copy constructor to be private to understand what I am talking about. 执行,但你可以声明复制构造函数是私有的,以了解我在说什么。

Example exObject = theInt; // here

This uses implicit conversion of int to Example, effected by the non-explicit constructor which accepts an int. 这使用int到Example的隐式转换,受接受int的非显式构造函数的影响。

This also requires the availability of copy constructor for Example, even though the compiler is allowed to omit copying the instance. 这也需要Example的拷贝构造函数的可用性,即使允许编译器省略复制实例。

int theInt1 = ctr; // here

This uses implicit conversion of Example to unsigned int, provided by the cast operator. 这使用了由actor运算符提供的Example到unsigned int的隐式转换。

Cast operators are normally avoided, since they tend to lead to confusing code, and you can mark single-argument constructors explicit, to disable implicit conversions to your class type. 通常避免使用转换运算符,因为它们往往会导致代码混乱,并且您可以将单参数构造函数显式标记,以禁用对类类型的隐式转换。 C++0x should add also the possibility to mark conversion operators explicit (so you'd need a static_cast to invoke them? - my compiler doesn't support them and all web resources seem to be concentrating on explicit conversion to bool). C ++ 0x还应该添加显式转换运算符的可能性(所以你需要一个static_cast来调用它们? - 我的编译器不支持它们,所有的web资源似乎都集中在显式转换为bool上)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM