C++Primer 第十四章

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++Primer 第十四章相关的知识,希望对你有一定的参考价值。

//1.当运算符作用于类类型运算对象时,可以通过运算符重载重新定义该运算符的含义。明智的使用运算符重载能令程序更加易于编写和阅读。

//2.重载的运算符是具有特殊名字的函数,它们由关键字operator和其后要定义的运算符号共同组成。和其它函数一样,重载的运算符也包含返回类型,参数列表以及函数体。

//3.除了重载函数调用符之外,其余的重载运算符不能含有默认实参。

//4.如果运算符函数是成员函数,则其左侧运算对象绑定到隐式的this指针。
//  对于运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数。即无法改变运算符作用于内置对象时候的操作。

//5.对于重载的运算符来说,其优先级和结合律是无法被改变的。

//6.某些运算符指定了运算对象的求值顺序。因为使用重载的运算符本事是一次函数调用,所以这些运算对象求值顺序的规则无法应用到重载的运算符上。
//  && || , 的求职顺序规则无法保留下来。 && || 的短路求值属性也无法保留,因此一般不对这些运算符进行重载。
//  C++语言已经定义了, 和 & 用于类类型对象时候的特殊含义,这一点与大多数运算符都不相同,所以一般也不要进行重载。

//7.当重载了==运算符的时候,一般也需要重载!=。重载了<则一般也要重载>。若重载了算数运算符或者位运算符,则最好也提供其复合版本。

//8.当我们定义重载的运算符的时候,必须首先决定是将其声明为类的成员函数还是类的非成员函数。其区别是:类的成员函数版本的重载运算符其左侧操作对象必须是该类的对象。
//  一般来说 = () [] -> 必须定义为类的成员函数版本。
//  重载的复合运算符一般来说作为类的成员函数,但非必须。
//  改变对象状态的运算符或与给定类型密切相关的运算符,比如 递减, 递增, 解引用 通常为作为类的成员函数。
//  具有对称性的运算符可能转换任意一端的运算对象,例如 算数 相等性 关系 位运算符等,通常应该是类的非成员函数(需按照类类型对象的位置,定义多个版本的重载运算符函数)。
//  尽量使重载的运算符与其内置的版本表现一致。

//9.如果存在唯一一种可靠的<定义,则应该考虑为这个类定义<运算符(关联容器和一些算法需要此运算符)。如果类同时还包含==,则当且仅当<定义和==结果是一致的时候才定义<(这里的结果一致的意思是:当不能满足==的时候,2个对象必须有一个是<另一个的)。

//10.下标运算符的内置版本是返回引用类型,所以其重载类型最好也返回引用类型,而且通常定义下标运算符的常量版本和非常量版本,防止作用于一个常量对象时不会给其返回的对象赋值。

//11.为了与内置版本保持一致,重载前置的递增递减运算符应该返回引用类型。后置的递增递减运算符应该按值返回。后置的递增递减运算符额外接受一个不被使用的int类型的实参(将会被置为0)来区别其前置版本。

//12.很多具有互相作用的运算符的重载,其工作可以交予其具有相关联关系的运算符重载函数完成,比如==的工作可以交予!=来完成等。

//13.箭头运算符永远不能丢掉其成员访问的这个基本含义。可以改变的是箭头从哪个对象当中获取成员,而箭头获取成员这一个事实则永远不变。所以:重载的箭头运算符必须返回类的指针或者自定义了箭头运算符的类的某个对象。
//   point->men;根据point的类型不同分别等价于:
//   A:(*point).men;            point是一个内置的指针类型
//   B:point.operator()->men;    point是类的一个对象。
class CTest
{
public:
    CTest()                    {str = "szn";}
    string* operator ->()    {return &str;}
public:
    string str;
};
CTest Test;
const char *pStr0 = Test->c_str();            //pStr0 = "szn"
const char *pStr1 = (&Test)->str.c_str();    //pStr1 = "szn"

//14.函数调用运算符可以重载为多个版本,相互之间在参数数量或者类型上有所区别。由于类的对象能存储状态,所以比起普通函数来说更加灵活。

//15.function位于头文件functional中,声明在命名空间std中,用于存储一个可调用对象。注意:重载的函数名字不能直接存入function类型的对象中,可以使用函数指针或lambda等来解决这个问题。
int Add(int value0, int value1)    {return value0 + value1;}
int Minus(int i, int j)            {return i - j;}

class CMultiply
{
public:
    CMultiply(){}
    int operator()(int value0, int value1){return value0 * value1;}
};

CMultiply multiply;
auto divide = [](int i, int j){return j == 0 ? 0 : i / j;};
auto minus = bind(Minus, _2, _1);

map<string, function<int (int , int)>> mapFun;
mapFun.insert(make_pair(string("+"), Add));
mapFun.insert(make_pair(string("-"), minus));
mapFun.insert(make_pair(string("*"), multiply));
mapFun.insert(make_pair(string("/"), divide));

int v0 = mapFun["+"](10, 5);    //v0 = 15
int v1 = mapFun["-"](10, 5);        //v1 = -5
int v2 = mapFun["*"](10, 5);    //v2 = 50
int v3 = mapFun["/"](10, 5);    //v3 = 2

//16.通过定义转换构造函数可以将指定类型的对象转换为类类型的对象。通过定义类型转换运算符可以将类类型的对象转换为指定类型的对象。转换构造函数和类型转换运算符共同组成了类类型转换。
//   在实际操作中,很少提供类的类型转换运算符,在大多数情况下,如果类型转换自动发生,用户可能感觉比较意外,而不是感觉受到了帮助。特殊的:对于类来说,定义向bool的类型转换还是比较普遍的。
class CTest
{
public:
    CTest() : value(0){}
    operator int() const {return value;}    //不能声明返回类型,形参列表必须为空,通常是const的。
private:
    int value;
};

CTest Test;
int value = Test;    //value = 0

//17.

 

以上是关于C++Primer 第十四章的主要内容,如果未能解决你的问题,请参考以下文章

C Primer Plus(第六版)第十四章 编程练习答案

C和指针 第十四章 习题

读书共享 Primer Plus C-part11

C语言第十四章:C语言补充

读书共享 Primer Plus C-part 12

《C与指针》第十四章练习