8.5.3 命名的对象是lvalue(2)
看起来似乎有很多代码,这是因为CText类具有重载的复制构造函数和赋值运算符版本,并定义了operator+()函数。CMessage类在实现自己的成员函数时使用了它们。同时还用输出语句来跟踪何时调用了每个函数。下面通过一个示例来练习这些类的用法。
试一试:重新导致效率低下
下面是一个简单的main()函数,它使用CMessage类的复制构造函数和赋值运算符:
- // Ex8_09.cpp Creeping inefficiencies
- #include <iostream>
- #include <cstring>
- using std::cout;
- using std::endl;
- // Insert CText class definition here...
- // Insert CMessage class definition here...
- int main()
- {
- CMessage motto1("The devil takes care of his own. ");
- CMessage motto2("If you sup with the devil use a long spoon.\n");
- cout << endl << " Executing: CMessage motto3(motto1+motto2); " << endl;
- CMessage motto3(motto1+motto2);
- cout << " Done!! " << endl << endl << "motto3 contains - ";
- motto3.ShowIt();
- CMessage motto4;
- cout << endl << " Executing: motto4 = motto3 + motto2; " << endl;
- motto4 = motto3 + motto2;
- cout << " Done!! " << endl << endl << "motto4 contains - ";
- motto4.ShowIt();
- cout << endl;
- return 0;
- }
示例说明
main()函数中相对很少的语句却产生了很多输出。我们只讨论几个有意思的地方。首先考虑执行下面这条语句产生的输出:
- CMessage motto3(motto1+motto2);
输出如下所示:
- CMessage add operator function called.
- CText constructor called.
- CMessage constructor called.
- CText constructor called.
- CText move assignment operator function called.
- CText destructor called.
- CText add operator function called.
- CText constructor called.
- CText move copy constructor called.
- CText destructor called.
- CText move assignment operator function called.
- CText destructor called.
- CText constructor called.
- CMessage move constructor called.
- CText assignment operator function called.
- CText destructor called.
要了解到底发生了些什么事,需要将输出消息与被调用函数中的代码关联起来。首先调用CMessage类的operator+()函数,将motto1与motto2连接起来。在operator+()函数体内,调用CMessage构造函数来创建消息对象,在此过程中,调用CText构造函数。一切进行得很顺利,直到到达输出的倒数第二行,即表明调用CMessage移动构造函数的那行输出后面。当此构造函数执行时,实参必须是临时的(即一个rvalue),因此,函数体中存储text成员值的赋值语句应该是CText对象的一个移动赋值操作,而不是复制赋值操作。于是问题就出现了,因为在CMessage移动构造函数内,aMess形参是一个lvalue(因为它有名称),尽管事实上我们肯定知道传递给函数的实参是一个rvalue。这就意味着aMess.text也是一个lvalue。如果不是,则会调用CMessage复制构造函数。
下面这条语句也会产生同样的问题:
- motto4 = motto3 + motto2;
如果看一下这条语句的输出,就会发现当调用CMessage对象的移动赋值运算符时会产生完全相同的问题。当实际上可以移动实参的text成员时,却对它进行了复制。