29

请帮助我了解 C++ 中的转换运算符是如何工作的。我在这里有一个简单的例子,我试图理解它,尽管编译器实际上是如何进行转换的还不是很清楚。

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;
}
4

4 回答 4

9

您可以使用调试器遍历该代码(和/或在每个构造函数和运算符上放置一个断点)以查看哪些构造函数和运算符被哪些行调用。

因为您没有明确定义它们,所以编译器还为您的类创建了隐藏/默认复制构造函数和赋值运算符。如果您想使用调试器查看调用它们的位置/时间,您可以显式定义它们(如下所示)。

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

Example& operator=(const Example& rhs)
{
    if (this != &rhs)
    {
        this->itsVal = rhs.itsVal;
    }
    return *this;
}
于 2009-09-05T15:58:57.447 回答
5
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;
}

在语句 1Example(int val)中调用构造函数。将其声明为explicit Example(int val),您将得到一个编译时错误,即不允许此构造函数进行隐式转换。

如果分配的值属于它们各自的参数类型,则所有单参数构造函数都会被隐式调用。在单参数构造函数之前使用explicit关键字会禁用隐式构造函数调用,从而禁用隐式转换。

如果构造函数被声明为显式 ie 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!

另请注意,在隐式构造函数调用和隐式转换的情况下,分配的值是一个右值,即使用左值(theInt)隐式创建的未命名对象,它告诉我们在隐式转换的情况下编译器转换

Example exObject = theInt;

Example exObject = Example(theInt);

因此(在 C++11 中)不要指望调用左值构造函数,因为您正在使用左值,即指定值theInt进行赋值。调用的是右值构造函数,因为分配的值实际上是使用左值创建的未命名对象。但是,如果您同时具有构造函数的左值和右值版本,则这适用。

在语句 2operator unsigned int()处被调用。只需将其视为具有奇怪名称的普通函数调用,并且在发生隐式转换时可以自动调用它。该函数返回的值是表达式中分配的值。而且由于在您的实现中,返回的值是一个 int ,它被正确分配给int theInt1.

确切地说,operator unsigned int()重载()运算符是强制转换运算符。int在您的情况下,每当将Example类的对象分配给int隐式类型转换 from Exampletoint并因此operator unsigned int()被调用时,它就会重载。所以,

int theInt1 = ctr;

相当于

int theInt1 = (int)ctr;
于 2013-03-03T17:20:58.483 回答
4
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()

如果您的编译器支持复制构造函数优化和返回值优化,您不会注意到

Example(const Example&)

执行,但是您可以将复制构造函数声明为私有以理解我在说什么。

于 2009-09-05T15:39:26.957 回答
2
Example exObject = theInt; // here

这使用 int 到 Example 的隐式转换,受接受 int 的非显式构造函数的影响。

这也需要 Example 的复制构造函数的可用性,即使允许编译器省略复制实例。

int theInt1 = ctr; // here

这使用强制转换运算符提供的 Example 到 unsigned int 的隐式转换。

通常避免使用强制转换运算符,因为它们往往会导致代码混乱,并且您可以将单参数构造函数标记为显式,以禁用对类类型的隐式转换。C++0x 还应该添加显式标记转换运算符的可能性(所以你需要一个 static_cast 来调用它们?-我的编译器不支持它们,并且所有 Web 资源似乎都专注于显式转换为 bool)。

于 2009-09-05T17:21:05.577 回答