C++ Primer阅读心得(第十四章)

1.不能重载的操作符,包括:  

  • : : (域操作符) 
  • .* (指针成员操作符)(这货很少用到啊)
  •  .(点操作符)  
  • ?: (问号表达式)

2.不建议重载的操作符,包括:

  • 因为无法保证求值顺序,不应该重载:逻辑与&&、逻辑或||、逗号运算符,
  • 重载operator&之后会造成很多问题(尤其是返回类型与默认返回类型不一致时),所以避免重载operator&。

3.操作符重载的基本规则:

  • 函数名称为:operator加上操作符
  • 有返回类型、函数体和参数列表
  • 一元操作符一个参数,二元操作符两个参数
  • 成为类成员的操作符重载第一个参数被默认为this,所以参数个数再减一
  • 只有调用操作符()可以有参数默认值,其他都不可以
  • 操作符重载函数或者是类成员,或者必须含有一个类类型的参数(所以你不能重载内置类型的操作符)
  • 只能重载已经存在的操作符,不能创造新的操作符(废话)
  • 重载操作符的优先级和结合律与默认的保持一致

是不是很啰嗦?在这里举个例子吧。

class Foo {
friend Foo operator+(const Foo&, const Foo&);
public:
    explicit Foo(int i):data(i){}
private:
    int data;
}

Foo operator+(const Foo &left, const Foo &right) {
    return Foo(left.data + right.data);
}

4.下面将各种操作符的重载列在如下表中:

操作符名称函数名返回值参数列表声明位置其他说明
输入输出操作符operator<<
operator>>
stream对象的引用
(保证>>和<<可以连续使用)
stream &s, const Type &t
(输入输出会改变流状态,所以引用不能为const)
类外friend
(因为第一个参数不能为this)
输入操作符必须处理流失败
输出操作符则不需要
算数操作符operator+
operator-
operator*
operator/
%^!~&|
Type的临时对象
(与内置类型的行为保持一致)
const Type &t1, const Type &t2类外friend推荐连同对应的复合运算符
一起定义,在内部可以使用
定义好的复合运算符来实现
对应的外部运算符
关系运算符operator==
operator!=
operator<
<= > >=
boolconst Type &t1, const Type &t2类外friend推荐成对定义,例如:定义
了==后把!=也定义了,并用
==实现!=;推荐定义<,因
为这样可以在更多的STL容
器中使用;最好能够保障传
递性
赋值运算符operator=Type &
(返回左侧对象的引用)
const Type & (拷贝赋值)
Type && (移动赋值)
以及其他各种类型
类member
(因为要返回左侧对象的引用)
只建议定义拷贝、移动以及
initializer_list版本的,其他
类型的版本容易让人费解;注意处理赋值给自己的情况(比较参数地址与this)
复合赋值运算符operator+=
operator-=
operator*=
operator/=
%=^=&=|=
<<= >>=
Type &const Type & 
以及其他各种类型
推荐类member不建议定义奇怪的,定以后
建议同时定义对应的运算
下标运算符operator[]类内对象类型的引用size_t类member
(因为要返回类内对象的引用)
建议同时定义const与非
const版本,来保证const
对象也可以使用
前置递增递减operator++
operator--
Type &类member
(因为改变了对象本身)
定义前置的同时建议也定
义后置版本
后置递增递减operator++
operator--
Type的临时对象
(递增递减前的拷贝)
int
(注意,int只是为了与前置版本区分,从来不用)
类member定义后置的同时建议也定
义前置版本
成员访问运算符operator*
operator->
Type &
Type *
类member推荐成对定义,注意保证->
的语义不变
函数调用运算符operator()任意任意类member
(不然就不是函数对象了)
可以有多个重载版本
类型转换运算符operator typetype类member注意类型转换的二义性

注意:解引用操作符operator*和operator->作用的是对象而不是指针,指针会使用语言默认的operator*和operator->,所以这两个重载是为了指针的container(例如:智能指针)准备的(妄想使用CRTP在成员访问前加点私活的可以放弃了)。

class Dref {
 public:
  Dref* operator->() { return this; }
  Dref& operator*() { return *this; }
  void do_sth() {...}
};

Dref *dref = new Dref;
dref->do_sth(); //使用指针调用,并没有调用重载的operator->,使用的是系统的
(*dref)->do_sth(); //使用对象调用的operator->才是你重载的
(*dref).do_sth(); //使用指针调用,并没有调用重载的operator*,使用的是系统的
(**dref).do_sth(); //使用对象调用的operator*才是你重载的

5.lambda表达式与函数对象:定义了函数调用操作符(operator())的类型的对象被称为函数对象,它们可以被调用函数那样子调用。

class Foo{
public:
    int operator() (int a, int b) const {
        return a - b;
    }
};

Foo minus; //函数对象
int c = minus(5, 4); //c = 1

而lambda表达式的背后,由编译器生成了一个重载了operator()的临时类的临时对象。值捕获的局部变量会被临时类的构造函数“拷贝”到类中;非mutable标记的lambda表达式对应的operator()是const的(所以不能修改捕获的变量);引用捕获的局部变量就不需要这一“拷贝”过程,而直接被编译器使用。lambda表达式和函数对象通常与泛型算法合作完成任务。

6.function类型:在c++当中,以下四种类型的对象是可以被调用的。

  • 函数
  • 函数指针
  • lambda表达式
  • 可调用对象

在混合使用它们的时候,相当的不方便,因为它们是四种不同类型的对象。为了解决这一问题,c++11中新增了function类型模板,以调用形式(“返回值-参数列表”)为Type,可以兼容以上全部类型,让它们像同一个类型的对象一样工作。

int add(int a, int b) {
    return a + b;
}
int (*add_ptr) (int, int) = add;
auto add_lambda = [](int a, int b) {
    return a + b;
}
class ADD {
    int operator() (int a, int b) {
        return a + b;
    }
};
ADD add_object;
function<int(int, int)> f1 = add;
function<int(int, int)> f2 = add_ptr;
function<int(int, int)> f3 = add_lambda;
function<int(int, int)> f4 = add_object;

注意:不能将重载函数直接放入function中,需要用函数指针明确指明或者lambda临时包装一下(这方法太经典了)。

7.显式类型转换符explicit:在c++11中,新增了显式类型转换符,用来阻止编译器利用定义好的类型转换符来进行隐式类型转换。增加了explicit的类型转换符必须显式调用类型转换才可以(static_cast等)。

class Foo {
public:
    Foo (int i):data(i){}
    explicit operator int () {return data;}
private:
    int data;
};
Foo f(1);
int a = 2 + f; //隐式转换,错误
int b = 2 + static_cast<int>(f); //ok,显式转换

注意:当表达式被当做条件处理时(if/while/do-while/for/问号表达式/&&/||/!),编译器会隐式的执行显式类型转换。

8.类型转换的best practice:除了定义显式bool类型转换符之外,不要定义其他的类型转换。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值