C++ Primer 【第四版】第十四章 重载操作符与转换
来源:互联网 发布:高一数学优化方案答案 编辑:程序博客网 时间:2024/06/06 00:00
重载操作符必须具有至少一个类类型或枚举类型的操作数。重载操作符不保证操作数的求值顺序,例如对 &&和 ||的重载版本不再具有“短路求值”的特性,两个操作数都要进行求值,而且不规定操作数的求值顺序。
对于优先级和结合性及操作数的数目都不变。
2。为Sales_item编写输入、输出。加以及复合赋值操作符的重载声明。
class Sales_item
{
friend std::istream& operator>> ( std::istream&, Sales_item& );
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
public:
Sales_item& operator += ( constSales_item& );
};
Sales_item operator+( const Sales_item&, const Sales_item& )
3。解释如下程序,假定Sales_item构造函数的参数是一个string,且不为explicit.解释如果构造函数为explicit会怎样。
string null_book = “0-000-00000-0”;
Sales_item item(cin);
item += null_book;
第一句:调用接受一个C风格的字符串形参的string构造函数,创建一个string临时对象,然后使用string复制构造函数用这个临时对象初始化string对象null_book,
第二句:从标准输入设备读入数据,创建Sales_item对象item。
第三句:首先调用接受一个string参数的Sales_item构造函数,创建一个临时对象,然后调用Sales_item的复合重载操作符+=,将这个Sales_item临时对象加到item对象上,
如果构造函数为explicit,则不能进行从string对象到Sales_item对象的隐式转换,第三句将不能被编译。
4。string和vector类都定义了一个重载的==,可用于比较这些类的对象,指出下面的表达式中应用了哪个==版本。
string s; vector<string> svec1,svec2;
“cobble” == “store” 应用了C++语言内置版本的重载==
svec1[0] == svec2[0];应用了string版本的重载==
svec1 == svec2 应用了vector版本的重载==
5。列出必须定义为类成员的操作符。
赋值 =,下标[],调用 (),成员访问箭头 ->
6。解释下面操作符是否应该为类成员,为什么?
(a)+ (b) += (c)++ (d) -> (e) << (f) && (g) == (h) ( )
+, <<, ==,&&通常定义为非成员;->和()必须定义为成员,否则会出现编译错误;+=和 ++会改变对象的状态,通常会定义为类成员。
7。为下面的ChecoutRecord类定义一个输出操作符:
class CheckoutRecord
{
public:
// ..
private:
doublebook_id;
stringtitle;
Datedate_borrowed;
Datedate_due;
pair<string,string>borrower;
vector<pair<string, string>* > wait_list;
};
ostream&
operator << (ostream&out, const CheckoutRecord& s)
{
out << s.book_id << "\t"<<s.title<<"\t" <<s.date_borrowed<<"\t" <<s.date_due
<< "\t";
out<< "borrower:" <<s.borrower.first<<"," << s.borrower.second <<endl;
out << "wait_list: " << endl;
for ( vector< pair<string,string>* >::const_iteratorit =s.wait_list.begin();
it != s.wait_list.end(); ++it )
{
out << "\t" << (*it)->first <<","<< (*it)->second<<endl;
}
return out;
}
8。在12.4节的习题中,你编写了下面某个类的框架: (b) Date
为所选择的类编写输出操作符。
#include<iostream>
using namespace std;
class Date
{
public:
Date() {}
Date( int y, int m, int d )
{
year = y; month = m; day = d;
}
friend ostream& operator<< (ostream&, const Date& );
private:
int year, month, day;
};
ostream&
operator<<( ostream& out, const Date& d )
{
out << " year: " <<d.year << "\t"
<< " month: "<< d.month << "\t"
<< " day: "<< d.day << endl;
}
int main()
{
Date dt(1988, 12, 01);
cout << dt << endl;
system("pause");
return 0;
}
9。给定下述输入,描述Sales_item输入操作符的行为。
(a) 0-201-99999-9 10 24.95
(b) 10 24.95 0-201-99999-9
(a)将0-201-99999-9读入赋给对象的isbn成员,将10给units_sold成员,revenue成员被设置为249.5
(b)首先将形参对象的isbn成员设置为10,然后因为输入的数据不符合要求,导致输入失败,从而执行else语句,将Sales_item对象复位为空对象,此时isbn为空string,units_sold和revenue都为0
10。下述Sales_item输入操作符有什么错误?
istream& operator>>( istream&in, Sales_item& s )
{
doubleprice;
in>> s.isbn >> s.units_sold >> price;
s.revenue= s.units_sold * price;
returnin;
}
如果将习题14.9中的数据作为输入,将会发生什么?
上述的输入操作符中缺少了对错误输入情况的判断与处理,会导致错误的情况发生。
(a)的输入没有问题,但是(b)的输入,将形参Sales_item对象的ISBN成员值为10,units_sold和revenue成员保持原值不变。
11。为14.2.1节习题中定义的CheckoutRecord类定义一个输入操作符,确保该类操作符处理输入错误。
classCheckoutRecord
{
public:
// …
friend istream&operator>>(istream&,CheckoutRecord&); // 声明为类的友元
// …
};
istream &operator>> (istream&in,CheckoutRecord&c)
{
cout << "Input bookid(double) and title(string) :\n";
in >> c.book_id >>c.title;
//Input Data data_borrowed and data_due
cout<< " Input data_borrowed (3 ints: year,month , day) :\n";
in>> c.date_borrowed;//.year >> c.date_borrowed.month >>c.date_borrowed.day;
//Input Data data_due and data_due
cout<< " Input data_due (3 ints: year, month, day) :\n";
in>> c.date_due;//.year >> c.date_due.month >> c.date_due.day;
//Input the pair<string,string> borrower
cout<< " Input the pair<string,string>borrower (string) :\n";
in>> c.borrower.first >>c.borrower.second;
if( !in )
{
c = CheckoutRecord();
return in;
}
//Input wait_list
cout<< " Input the wait_list (string):\n";
c.wait_list.clear();
while( in )
{
pair<string,string> *ppr = new pair<string,string>;
in >> ppr->first>>ppr->second;
if ( !in )
{
delete ppr;
return in;
}
c.wait_list.push_back(ppr );
}
return in;
}
输入错误的情况:
输入正确的情况:
12。编写Sales_item操作符,用+进行实际加法,而+=调用+。与本节中操作符的实现方法相比较,讨论这个方法的缺点。
Sales_itemSales_item::operator+( const Sales_item& rhs )
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
将下面定义的非成员+=操作符声明为类Sales_item的友元:
Sales_itemoperator+=( Sales_item& lhs, const Sales_item& rhs )
{
lhs = lhs + rhs;
return lhs;
}
这个方法缺点:在+=操作中需要创建和撤销一个临时Sales_item对象,来保存+操作的结果,没有本节中的方法简单有效。
13。如果有,你认为Sales_item还应该有哪些其他的算术操作符?定义你认为的该类应包含的那些。
还应有-操作符,定义为类的非成员,相应地还应该有-=复合操作符并定义为类的成员。
Sales_item&Sales_item::operator-=( const Salse_item& rhs )
{
units_sold -= rhs.units_sold;
revenue -= rhs.revenue;
return *this;
}
Sales_item operator-(const Sales_item &lhs, const Sales_item & rhs )
{
Sales_item ret(lhs);
ret -= rhs;
return ret;
}
14。定义一个赋值操作符,将isbn赋值给Sales_item对象。
Sales_item&Sales_item::operator=( const string & s )
{
sbn = s;
return *this;
}
10。为14.2.1节习题中介绍的CheckoutRecord类定义赋值操作符。
主函数中定义了两个CheckoutRecord类的对象,调用了CheckoutRecord类的 =赋值操作符,效果如下截图:
int_tmain(int argc, _TCHAR* argv[])
{
CheckoutRecordc1;
cin>> c1;
CheckoutRecordc2;
c2 = c1; // 调用了类的赋值操作符=
std::cout <<c2<< std::endl;//输出对象c2的内容
system("pause");
return0;
}
// CheckoutRecord类中赋值操作符定义为:
//重载操作符=
CheckoutRecord&CheckoutRecord::operator =(const CheckoutRecord&cr)
{
book_id= cr.book_id;
title= cr.title;
date_borrowed= cr.date_borrowed;//前提:必须在Date类里也重载操作符=
date_due= cr.date_due; // as before
// 对pair进行赋值操作
borrower.first =cr.borrower.first;
borrower.second =cr.borrower.second;
// 对vector进行赋值操作
wait_list.clear();// 首先清空
for ( vector<pair<string,string>*>::const_iteratorit= cr.wait_list.begin();
it != cr.wait_list.end(); ++it )
{
pair<string,string>*ppr = new pair<string,string>;
ppr->first = (*it)->first;
ppr->second = (*it)->second;
wait_list.push_back(ppr );
}
return*this;
}
16。CheckoutRecord类还应该定义其他赋值操作符吗?如果是,解释哪些类型应该用作操作数并解释为什么。为这些类型实现赋值操作符。
从应用角度考虑,可能会修改预约时间date_due,可通过设置新的赋值操作符来实现;或者是往wait_list里添加排队读者,也可以通过设置新的赋值操作符来实现。
// set new date_due
CheckoutRecord&CheckoutRecord::operator=( const& new_due )
{
date_due = new_due;
return *this;
}
// add new readerswho wait for some books
CheckoutRecord&CheckoutRecord::operator=( const std::pair<string,string>& new_waiter)
{
pair<string,string> *ppr = newpair<string, string>;
*ppr = new_waiter;
wait_list.push_back( ppr );
return *this;
}
17。14.2.1节习题中定义了一个CheckoutRecord类,为该类定义一个下标操作符,从等待列表中返回一个名字。
下标重载:
pair<string,string>& CheckoutRecord::operator[ ]
(const vector< pair<string, string>* >::size_type index )
{
return*wait_list.at(index );
}
//下标操作符重载
constpair<string, string>&CheckoutRecord::operator[]
(const vector< pair<string, string>* >::size_type index ) const
{
return*wait_list.at(index );
}
18。讨论用下标操作符实现这个操作的优缺点。
优点:使用简单。
缺点:操作的语义不够清楚,因为CheckoutRecord不是一个通常意义上的容器,而且等待者也不是CheckoutRecord容器中的一个元素,不易使人弄明白怎样用。
19。提出另一种方法定义这个操作。
可以将这个操作定义成普通的函数, pair<string, string>& get_a_waiter(const size_t index ) 和 const pair<string, string>&get_a_waiter ( const size_t index ) const.
20。在ScreenPtr类的概略定义中,声明但没有定义赋值操作符,请实现ScreenPtr赋值操作符。
ScreenPtr&operator=( const ScreenPtr& sp )
{
++sp.ptr->use;
if ( --ptr->use == 0 )
delete ptr;
ptr = sp.ptr;
return *this;
}
21。定义一个类,该类保存一个指向ScreenPtr的指针。为该类定义一个重载的箭头操作符。
class NoName
{
public:
NoName( *p ): ps( new ScreenPtr(p) ) { }
ScreenPtr operator->( )
{
return *ps;
}
const ScreenPtr operator->( ) const
{
return *ps;
}
~NoName()
{
delete ps;
}
private:
ScreenPtr *ps;
};
22。智能指针可能应该定义相等操作符和不等操作符,以便测试两个指针是否相等或不等。将这些操作加入到ScreenPtr类。
class ScreenPtr
{
public:
// …
friend inline bool operator==( const ScreenPtr&, const ScreenPtr &);
friend inline bool operator!=( const ScreenPtr&, const ScreenPtr &);
private:
ScrPtr *ptr;
};
// operator ==
inline booloperator==( const ScreenPtr &p1, const ScreenPtr &p2 )
{
return p1.ptr == p2.ptr;
}
// operator !=
inline booloperator!=( const ScreenPtr &p1, const ScreenPtr &p2 )
{
return !( p1.ptr == p2-.ptr );
}
23。CheckedPtr类表示指向数组的指针。为该类重载下标操作符和解引用操作符。使操作符确保CheckedPtr有效:它应该不可能对超出数组末端的元素进行解引用或索引。
//下标操作符重载
int&CheckedPtr::operator[]( const size_t index )
{
if ( beg + index >= end )
throw out_ot_range( “ invalidindex“ );
return *( beg + index );
}
const int& CheckedPtr::operator[] ( const size_t index ) const
{
if ( beg + index >= end )
throw out_ot_range( “ invalidindex“ );
return *( beg + index );
}
//解引用操作符重载
intCheckedPtr::operator*()
{
if ( curr == end )
throw out_of_range( “ invalidcurrent pointer” );
return *curr;
}
const int&CheckedPtr::operator*() const
{
if ( curr == end )
throw out_of_range(“ invalidcurrent pointer”);
return *curr;
}
24。习题14.23中定义的解引用操作符或下标操作符,是否也应该检查对数组起点之前的元素进行的解引用或索引?解释你的答案。
对于下标操作符,应该进行检查,因为当用户给出的下标索引值小于0时,编译器不会出现编译错误,而会出现运行时错误。应修改为:
//下标操作符重载
int&CheckedPtr::operator[]( const size_t index )
{
if ( beg + index >= end || beg +index < beg )
throw out_ot_range( “ invalidindex“ );
return *( beg + index );
}
const int& CheckedPtr::operator[] ( const size_t index ) const
{
if ( beg + index >= end || beg +index < beg )
throw out_ot_range( “ invalidindex“ );
return *( beg + index );
}
而对于解引用操作符,返回curr所指向的数组元素,在创建对象时已经将curr初始化为指向数组的第一个元素,只有当执行—操作时才会对curr进行减的操作,而—操作符已经对curr的值与数组起点进行了检查,所以不用再在这里检查。
25。为了表现得像数组指针,CheckedPtr类应实现相等和关系操作符,以便确定两个CheckedPtr对象是否相等,或者一个小于另一个,诸如此类。为CheckedPtr类增加这些操作。
应将这些操作符声明为CheckedPtr的友元。
//相等操作符
bool operator==(const CheckedPtr& lhs, const CheckedPtr& rhs )
{
return lhs.beg == rhs.beg &&lhs.end == rhs.end && lhs.curr == rhs.curr;
}
bool operator!=(const CheckedPtr & lhs, const CheckedPtr& rhs )
{
return !( lhs == rhs );
}
//关系操作符
bool operator<(const CheckedPtr & lhs, const CheckedPtr& rhs )
{
return lhs.beg == rhs.beg &&lhs.end == rhs.end
&& lhs.curr <rhs.curr;
}
bool operator>(const CheckedPtr & lhs, const CheckedPtr& rhs )
{
return lhs.beg == rhs.beg &&lhs.end == rhs.end
&& lhs.curr >rhs.curr;
}
bool operator<=(const CheckedPtr & lhs, const CheckedPtr& rhs )
{
return !( lhs.curr > rhs.curr );
}
bool operator >=(const CheckedPtr & lhs, const CheckedPtr& rhs )
{
return !( lhs.curr < rhs.curr );
}
26。为CheckedPtr类定义加法或减法,以便这些操作符实现指针运算。
将这两个操作符声明为类的友元。
CheckedPtr operator+(const CheckedPtr& lhs, const size_t n )
{
CheckedPtr temp( lhs );
temp.curr += n;
if ( temp.curr > temp.end )
throw out_of_range(“ Too large n,over.”);
return temp;
}
CheckedPtr operator-(const CheckedPtr& lhs, const size_t n )
{
CheckedPtr temp( lhs );
temp.curr -= n;
if ( temp.curr < temp.beg )
throw out_of_range(“ Too large n,over.”);
return temp;
}
用到了复制构造函数,定义为:
CheckedPtr::CheckedPtr(const CheckedPtr& cp ):
beg( cp.beg ), end(cp.end ), curr( cp.curr )
{ }
27。讨论允许将空数组实参传给CheckedPtr构造函数的优缺点。
优点:构造函数的定义简单。缺点:导致构造的对象没有指向有效的数组,从而失去使用价值。应该在构造函数里控制参数确保beg<end.
28。没有定义自增和自减操作符的const版本,为什么?
const所修饰的operator,不可以改变对象,而自增和自减肯定改变了对象,与const意义相反,所以不定义const版本。
29。我们也没有实现箭头操作符,为什么?
因为此类所指向的是int型数组,int型为内置类型,而箭头操作符必须返回一个类类型的指针,所以不实现。
30。定义一个CheckedPtr版本,保存Screen数组。为该类实现重载的自增、自减。解引用和箭头等操作符。
class CheckedPtr
{
public:
CheckedPtr( Screen *b, Screen *e ): beg(b ), end( e ), curr( b ) { }
// 自增、自减
CheckPtr& operator++();
CheckPtr& operator—();
CheckPtr& operator++( int );
CheckPtr& operator—( int );
// 箭头操作符
Screen* operator->();
const Screen* operator->() const;
// 解引用操作
Screen& operator*();
const Screen& operator*();
private:
Screen *beg;
Screen *end;
Screen *curr;
};
CheckPtr&CheckPtr::operator++()
{
if ( curr == end )
throw out_of_range( “incrementpast the end of CheckedPtr”);
++curr;
return *this;
}
CheckPtr&CheckPtr::operator—()
{
if ( curr == begin )
throw out_of_range( “decrementpast the beginning of CheckedPtr”);
--curr;
return *this;
}
//后缀式
CheckPtr&CheckPtr::operator++( int )
{
CheckedPtr temp( *this );
++*this;
return temp;
}
CheckPtr&CheckPtr::operator—( int )
{
CheckedPtr temp( *this );
--*this;
return temp;
}
//箭头操作符
Screen*CheckedPtr::operator->()
{
return curr;
}
const Screen*CheckedPtr::operator->() const
{
return curr;
}
Screen&CheckedPtr::operator*()
{
if ( curr == end )
throw out_of_range( “invalidcurrent pointer.”);
return *curr;
}
const Screen&CheckedPtr::operator*() const
{
if ( curr == end )
throw out_of_range( “invalidcurrent pointer.”);
return *curr;
}
31。定义一个函数对象执行“如果……则……否则”操作;该函数对象应接受三个形参;它应该测试第一个形参;如果测试成功,则返回第二个形参;否则,返回第三个形参。
class NoName
{
public:
NoName() { }
NoName( int i1, int i2, int i3 ): iVal1(i1 ), iVal2( i2 ), iVal3( i3) { }
int operator() ( int i1, int i2, int i3 )
{
return i1? i2: i3;
}
private:
int iVal1;
int iVal2;
int iVal3;
};
32。一个重载的函数调用操作符可以接受多少个操作数?
0个或多个。
33。使用标准库算法和GT_cls类,编写一个程序查找序列中第一个比指定值大的元素。
//14.33_Gt_cls_and_algorithm.cpp :定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
usingnamespace std;
classGT_cls
{
public:
GT_cls(conststring gW =" " ) : givenWord(gW ) { }
bool operator() (const string &s )
{
return( s >givenWord);
}
private:
std::stringgivenWord;
};
int_tmain(int argc, _TCHAR* argv[])
{
std::cout <<"Input some words( ctrl + z to end ):" << std::endl;
vector<string>text;
stringword;
while (std::cin>>word )
{
text.push_back(word );
} // end of input the text
// input thegiven word
std::cin.clear();
std::cout <<" Then, input one given word:\t";
stringgWord;
std::cin >>gWord;
// deal with text , to realize find the first word which is bigger than the givenword
vector<string>::iteratorit =find_if(text.begin(),text.end(),GT_cls( gWord ));
if ( it != text.end() )
std::cout <<"\nThen the first word in the text you input," <<std::endl
<<" \twhich is bigger than the given wordis:" <<std::endl
<<"\t" << *it <<std::endl;
system("pause");
return0;
}
34。编写类似于GT_cls的类,但测试两个值是否相等。使用该对象和标准库算法编写程序,替换序列中给定值的所有实例。
//14.34_GT_cls.cpp :定义控制台应用程序的入口点。
#include"stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
usingnamespace std;
classGT_cls
{
public:
GT_cls(intiVal = 0 ): val(iVal ){ }
bool operator() (const int & iv )
{
return( iv ==val);
}
private:
int val;
};
int_tmain(int argc, _TCHAR* argv[])
{
std::cout <<"Input some nums( ctrl + z to end ):" << std::endl;
vector<int>iVec;
int iVal;
while (std::cin>>iVal)
{
iVec.push_back(iVal );
} // end of input the iVec
cin.clear();
cout<< " Input a num which will be replaced:\t";
int rp;
cin>> rp;
cout<< " Input a given num to insert:\t";
int givenNum;
cin>> givenNum;
// replace
replace_if(iVec.begin(),iVec.end(),GT_cls( rp ), givenNum );
cout<< " Now , the new vector<int>iVec, is : \n\t";
for ( vector<int>::iteratorit = iVec.begin();it != iVec.end(); ++it )
{
cout<< *it <<"";
}
system("pause");
return0;
}
35。编写类似于GT_cls的类,但测试给定string对象的长度是否与其边界相匹配。报告输入中有多少单词的长度在1到10之间。
//14.35_BT_cls.cpp :定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
usingnamespace std;
classBT_cls
{
public:
BT_cls(size_t len1 = 0, size_t len2 =0 )
{
if( len1 <len2)
{
minlen = len1;
maxlen = len2;
}
else
{
minlen = len2;
maxlen = len1;
}
}
bool operator() (const string &s )
{
return( s.size()>=minlen && s.size() <=maxlen );
}
private:
std::string::size_typeminlen, maxlen;
};
boolisShorter( conststring &s1, const string &s2 )
{
return s1.size() < s2.size();
}
int_tmain(int argc, _TCHAR* argv[])
{
std::cout <<"Input some words( ctrl + z to end ):" << std::endl;
vector<string>text;
stringword;
while (std::cin>>word )
{
text.push_back(word );
} // end of input the text
// deal with text
sort( text.begin(),text.end() );
text.erase(unique( text.begin(),text.end() ), text.end() );
stable_sort(text.begin(),text.end(),isShorter );
// to counthow many words' length are between 1-10
vector<string>::size_typecnt =count_if(text.begin(),text.end(),BT_cls( 1, 10 ));
std::cout << " There are " <<cnt << "words' length is between 1-10." <<std::endl;
system("pause");
return0;
}
36。修改前一段程序以报告在1到9之间以及10以上的单词的数目。
// 14.36_BT_cls_Words.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
usingnamespace std;
classBT_cls
{
public:
BT_cls(size_t len1 = 0, size_t len2 =0 ) : minlen(len1 ), maxlen(len2 ) { }
bool operator() (const string &s )
{
return( s.size()>=minlen && s.size() <=maxlen );
}
private:
std::string::size_typeminlen, maxlen;
};
int_tmain(int argc, _TCHAR* argv[])
{
std::cout <<"Input some words( ctrl + z to end ):" << std::endl;
vector<string>text;
stringword;
while (std::cin>>word )
{
text.push_back(word );
} // end of input the text
std::cin.clear();
// deal with text , to count how many words' length are between 1-9
size_tcnt =count_if(text.begin(),text.end(),BT_cls( 1, 9 )) ;
std::cout <<"\nThereare "<< cnt <<" words' length are 1-9." << std::endl;
cout<< " And there are " <<text.size() -cnt <<"words' length is 10 or more." << endl;
system("pause");
return0;
}
37。使用标准库函数对象和函数适配器,定义一个对象用于:
(a)查找大于1024的所有值。
(b)查找不等于pooh的所有字符串。
(c)将所有值乘以2
(a) find_if(vec.begin(), vec.end(), bind2nd( greater<int>(), 1024 ) );
(b) find_if (svec.begin(), svec.end(), bind2nd( not_equal_to<string>(), “pooh”);
(c) transform(ivec.begin(), ivec.end(), ivec.begin(), bind2nd( multiplies<int>(), 2 ));
38。最后一个count_if调用中,用not1将bind2dn(less_equal<int>(),10 ) 的结果求反。为什么使用not1而不用not2?
not1用于将一元函数对象的真值求反,not2用于将二元函数对象的真值求反,函数适配器bind2nd将less_equal<int>对象的右操作数绑定到10,从而less_equal对象由二元函数对象转换为一元函数对象,所以用not1求反。
39。使用标准库函数对象代替GT_cls来查找指定长度的单词。
输入一个指定长度:
vector<string>text;
// … // input words into text
string::size_typelen;
cin >> len;
string *w;
for (vector<string>::iterator it = text.begin(); it != text.end(); ++it )
{
w = find_if ( it, text.end(), bind2nd(equal_to<string::size_type>(), len) );
}
cout << “ Thewords whose length is “<< len << ” was found.,Itis:”
<< *w <<endl;
40。编写可将Sales_item对象转换为string类型和double类型的操作符。你认为这些操作符应返回什么值?你认为定义这些操作符是个好办法吗?解释你的结论。
Sales_item::operatorstring() const
{
return isbn;
}
Sales_item::operatordouble() const
{
return revenue;
}
不是好办法,因为不必在需要stirng类型和double类型对象的地方使用Sales_item对象,这种做法没有太大用处。
41。解释这两个转换操作符之间的不同:
class Integral
{
public:
operatorconst int();
operatorint() const;
};
不同:前者将对象转换为const int值,后者将对象转换为int值,前者太严格,限制使用在可以使用const int 值的地方,只保留后者,将变得更为通用。
42。为14.2.1节习题中的CheckoutRecord类定义到bool的转换操作符。
CheckoutRecord::operatorbool() const
{
return wair_list.empty();
}
43。解释bool转换操作符做了什么。这是这个CheckoutRecord类型转换唯一可能的含义吗?解释你是否认为这个转换是一种转换操作的良好使用。
将wait_list为空的CheckoutRecord对象转换为bool类型的true,将不为空的对象转换为false.
不是唯一的含义,还可以将bool转换符定义为当前日期是否已经超过date_due,即判断某本借出的书是否已经过期。
上述定义可用于判断是否有读者在等待借阅,当某本书被归还时,可以用相应的CheckoutRecord对象作为判断条件以确定是否通知该书的等待着。因此这个转换是一种转换操作的良好使用。
44。为下述每个初始化列出可能的类类型转换序列。每个初始化的结果是什么?
class LongDouble
{
public:
operatordouble();
operatorfloat();
};
LongDouble ldObj;
(a) int ex1 = ldObj; (b) float ex2 = ldObj;
(a)既可以先使用从Longdouble到double的转换操作,再是偶那个从double到int的标准转换,也可以使用从LongDouble到float的转换操作,再使用从float到int的标准转换,二者没有优劣之分,具有二义性。
(b)使用从LongDouble到float的转换操作,将ldObj对象转换为float值用于初始化ex2
45。哪个calc()函数是如下函数调用的最佳可行函数?列出调用每个函数所需的转换序列,并解释为什么所选定的就是最佳可行函数。
class LongDouble
{
public:
LongDouble(double );
//…
};
void calc( int );
void calc( LongDouble );
double dval;
calc( dval ); // which function?
最佳可行函数是void calc(int), 调用此函数的转换为:将实参double类型转换为int类型的,为标准转换;调用void calc( LongDouble)函数时,将实参从double转换为LongDouble类型,为类类型转换,因为标准转换优于类类型转换,所以第一个函数为最佳可行函数。
46。对于main中的加操作,哪个operator是最佳可行函数?列出候选函数。可行函数以及对每个可行函数中实参的类型转换。
class Complex
{
public:
Complex(double );
//…
};
class LongDouble
{
friendLongDouble operator+( LongDouble, int );
public:
LongDouble(int );
operatordouble();
LongDoubleoperator+( const Complex & );
//…
};
LongDouble operator+( const LongDouble&, double);
LongDouble ld( 16.08 );
double res = ld + 15.05; // whichoperator+?
(a)内置类型的+操作符
将ld从LongDouble转换为double类型。
(b)友元friend LongDouble operator+( LongDouble, int );
将 15.05从double类型转换为int类型(使用标准转换)。
(c) LongDoubleoperator+( const Complex & );
将15.05转换为Complex型,使用Complex类的构造函数。
(d)全局函数LongDoubleoperator+( const LongDouble &, double);
无需进行类型转换,因此虽然这4个都为候选函数,和可行函数,但是这个是最佳可行函数。
- C++ Primer 【第四版】第十四章 重载操作符与转换
- C++ Primer 4 第十四章 重载操作符与转换
- c++ primer读书笔记-第十四章 重载操作符与转换
- C++ Primer 第十四章 重载操作符与转换
- C++Primer学习笔记第十四章(14/18)类 重载操作与转换
- 第十四章:重载操作符与转换
- 第十四章 重载操作符与转换
- 第十四章 重载操作符与转换
- C++ Primer复习和学习笔记 第十四章 重载操作符与转换
- 《C++primer(第五版)》学习之路-第十四章:重载运算与类型转换
- C++primer第五版笔记-第十四章重载运算与类型转换
- c++primer(第五版) 第十四章 重载运算与类型转换习题答案
- 《C++ Primer》 第四版 第14章 重载操作符与转换
- 第十四章 重载操作与转换(一)
- 第十四章 重载操作与转换(二)
- C++ Primer : 第十四章 : 重载运算与类型转换之重载运算符
- c++primer第十四章重载运算与类型转换小结-14
- 《C++Primer》3.15重载操作符与转换
- 吐槽
- Alex 的 Hadoop 菜鸟教程: 第6课 Hbase 安装教程
- cocos2dx3.2 学习笔记(2)--ActionManagerTest(3)
- MakeFile基础知识(三)
- wx.python事件的绑定
- C++ Primer 【第四版】第十四章 重载操作符与转换
- 关于IOS中的KeyChain(转载自网上)
- 扑克牌洗牌算法
- 通过工具类将图片转成圆形图,并加上边框
- GPS数据包解析
- 三大发生的发生的发
- X86架构下VMM的挑战
- ffmpeg的内部Video Buffer管理和传送机制
- UFLDL稀疏编码器练习实现