2013-10-15 56 views
2

由于各种无聊的原因,我需要一个盒装的int类,它主要充当一个int,但是它是一个从基础继承的类,所以它可以与对象层次结构的其他部分一起工作。我包含了一个构造函数,它接受一个int类型以及一个int类型转换,这样我就可以轻松地将我的盒装int与代码中的常量int进行混合。但是,我看到一个非常奇怪的行为,我无法弄清楚:当我从函数返回盒装int时,我希望它使用我的拷贝构造函数来引用另一个BoxedInt。然而,它将我的盒装int转换为int,然后使用我的int构造函数。这会导致问题,因为在我的实际代码库中,在这种情况下,我想要复制其他基类属性,并且通过使用此构造函数路径来丢失它们。这是有问题的代码:为什么C++选择将我的返回值转换为int?

class BoxedInt 
{ 
private: 
    int m_int; 
public: 
    BoxedInt():m_int(0) 
    { 
     trace(L"Constructed with nothing"); 
    } 

    BoxedInt(int val):m_int(val) 
    { 
     trace(L"Constructed with int"); 
    } 

    BoxedInt(BoxedInt& val) 
    { 
     trace(L"Constructed with reference"); 
     m_int = val.m_int; 
    } 

    operator int() 
    { 
     trace(L"Cast to int"); 
     return m_int; 
    } 
}; 

BoxedInt funky() 
{ 
    BoxedInt TempInt = 1; 
    return TempInt; 
} 

int main(int argc, char* argv[]) 
{ 
    trace(L"Start"); 
    BoxedInt test1 = 1; 
    trace(L"Copying"); 
    BoxedInt test2 = test1; 
    trace(L"Assigning from return value"); 
    BoxedInt test3 = funky(); 
    trace(L"Done"); 
    return 0; 
} 

当这个运行时,这里的输出:

Start 
Constructed with int 
Copying 
Constructed with reference 
Assigning from return value 
Constructed with int 
Constructed with reference 
Cast to int 
Constructed with int 
Done 

所以,当我分配一个值到另一个参考依据构造时,我会期望。但是,当我将函数的返回值赋给BoxedInt时,出于某种原因编译器决定将其转换为int,然后使用int构造函数。我的C++很生疏,而且在编译器这个奇怪的编译器决策底部,我似乎无法抵消。有任何想法吗?

+0

阅读关于显式关键字http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean – fasked

+0

编译器不会**将返回值转换为' int',它**转换**它。强制转换是您在源代码中编写的内容,以告知编译器进行转换。同样,'operator int'是一个**转换操作符**,不是一个强制转换。 –

回答

9

你的拷贝构造函数接受一个非const的引用,所以它不能与临时调用 。 funky()的返回值是一个临时值,因此复制构造函数不能用 来构造test3

使复制构造函数采取const引用,它应该 是好的。

+2

我觉得自己像一个白痴,我注意到,只要我发布,但删除已经太迟了!你们太快了。 –

+0

@Raja我不知道这是一个很好的网页来引用。 Herb很好地解释了这些问题,但他使用的例子是一种情况,你不应该使用引用来开始,const或其他;事实上他没有提到这一点,可能会向很多读者表明,这里使用const引用是很好的编程实践。 –

+0

好点詹姆斯。我删除了该链接。 – Raja

5

您的复制构造函数需要一个非const引用,这意味着您不能将临时参数绑定到参数,这正是您想要的返回方法所做的。因此,编译器选择其他路由。

改变你的拷贝构造:

BoxedInt(const BoxedInt &val) { 

事实上,锵3.4 gives an error因为BoxedInt test1 = 1;的。

+1

我认为铿锵是对的。复制初始化需要可访问的拷贝构造函数。而且我会解释它的方式,这意味着一个可访问的拷贝构造函数来复制至少在理论上构建的临时文件。 –

+0

@JamesKanze,我完全同意。 – chris

+2

GCC 4.8.1也会在'BoxedInt test1 = 1;'中投诉,因为它应该。 –

1

我相信这个问题(或其中一人)是拷贝构造函数签名:

BoxedInt(BoxedInt& val) 

应该

BoxedInt(const BoxedInt& val) 
相关问题