C++手稿:运算符重载

运算符重载

运算符重载就是对已有的C++运算符赋予更多的语义,让一个运算符可以作用于其他的数据类型。 典型地,让运算符接受一个类的对象作为参数。通常有两种方式来重载一个运算符:

  1. 声明一个普通函数,作为类的友元。
  2. 声明为类的成员方法。

事实上,运算符的本质是函数。每个运算符调用会转换为函数调用,运算符的操作数转换为函数参数。 运算符的重载本质上是方法的重载。

这些运算符不允许重载:..*::?:sizeof

重载为普通函数

重载为普通函数时,参数的个数为运算符的目数:

CPerson operator+(const CPerson& male, const CPerson& female){
    return CPerson(male.name + female.name);
};

CPerson male("Bob"), female("Alice");
CPerson child1 = male + female;
// 等价于
CPerson child2 = operator+(male, female);

这些运算符必须重载为成员函数:()[]->=

重载为成员函数

重载为成员函数时,参数的个数为运算符的目数-1:

class CPerson{
    string name;
public:
    CPerson(string name_):name(name_){}
    CPerson operator+(const CPerson& female){
        return CPerson(name + female.name);
    }
};

CPerson male("Bob"), female("Alice");
CPerson child1 = male + female;
// 等价于
CPerson child2 = male.operator+(female);

重载赋值运算符

接下来列举一些常见的运算符重载实践。当一个对象赋值给另一个对象的变量时,赋值运算符被调用。

const CPerson& operator=(const CPerson& p){
    name = p.name;
    return *this;
};
  • 参数为const,因为不需要改变原有对象。

    能使用const时,尽量使用它。详情见:Effective
    C++ 笔记

  • 参数、返回值为引用,因为直接传参会生成一个新的对象,低效。
  • 返回值为CPerson类型,这样可以支持连等:a
    = b = c
  • 返回值为const,赋值的结果不应当被改变。

对于赋值运算符,更高效的做法是“copy and swap”:

const CPerson& operator=(CPerson p){
    std::swap(name, p.name);
    return *this;
};

事实上赋值运算符有两点重要的关注:

  1. 自我赋值的正确性。一些失败的实现中,会先deletethis的资源。

    上述代码中用std::swap保证了自我赋值的正确性。当然你也可以自己写一个健壮的swap函数。

  2. 异常安全。当拷贝失败时,原有对象不可破坏。

    上述代码中,拷贝发生在进入函数之前,提供了强烈的异常安全。同时编译器来完成拷贝比函数中手动拷贝更加高效。

重载流插入运算符

ostream& operator<<(ostream& o, const CPerson& p){
    cout<<p.name<<endl;
    return o;
}

返回ostream&也是为了支持链式调用:`cout<<p1<<p2;

事实上,operator<<(int)ostream的成员函数:

class ostream{
    ostream & operator<<(int n){
        // print n
        return *this;
    }
};

重载下标运算符

class Array{
int *ptr;
public:
    int size;
    Array(int n=64):size(n){
        ptr = new int[n];
    }
    Array(Array& old){
        new (this) A(old.size);
        memcpy(ptr, old.ptr, old.size * sizeof(int));
    }
    ~ Array(){
        delete [] ptr;
    }
    int& operator[](int i){
        return ptr[i];
    }
    const Array& operator= (const Array rhs){
        swap(*this, rhs);
        return *this;
    }
};
  • new
    (this) A()
    是“placement new”表达式,在已存在的内存上分配对象。
  • “copy and swap”方式进行赋值运算符重载。

自增运算符

自增、自减运算符分为前置运算符和后置运算符。虽然逻辑上都是一元的,但在定义重载方法时, C++规定:前置运算符有一个参数,后置运算符有两个参数。

当然第二个参数是没用的,只是为了生成不同的函数签名。

例如:

CPerson& operator++(CPerson&);
CPerson operator++(CPerson&, int);

可以看到后置自加运算符的返回值为CPerson,会在函数返回时生成一个新的对象,
这是因为它的表达式值定义为自加之前的值。 因此,通常我们尽量使用前置的自加、自减运算符:

for(vector<int> i = v.begin(); i != v.end(); ++i);

强制转换运算符

基本数据类型到对象的转换是靠重载构造函数来实现的; 对象到基本数据类型的转换是靠重载强制转换运算符来实现的:

class CPerson{
    int age;
public:
    CPerson(int age_):age(age_){}
    operator int(){
        return n;
    }
};

CPerson p;
(int) p == p.int();

下面的例子展示了上述两种转换何时被调用:

CPerson p1(1);
cout<<p1 <<endl;      // p1.int()
cout<<p1 + 3<<endl;   // CPerson(3),p.int();
p1 = 3 + p1;          // p1.int(),CPerson(4)


除非注明,本博客文章均为原创,转载请以链接形式标明本文地址: http://harttle.com/2015/06/25/operator-overload.html

版权声明:本文为博主原创文章,转载请附上原文链接。

时间: 2024-10-11 18:55:21

C++手稿:运算符重载的相关文章

关于运算符重载

运算符重载需遵循以下原则: 1.除了类所属关系运算符".".成员指针运算符".*".作用域运算符"::".sizeof运算符.三目运算符"?:"之外,C++中所有的运算符都可以进行重载 2.重载运算符限制在C++已有的运算符范围内,不允许创建新的运算符 3.重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数的个数及语法结构 4.运算符重载不能改变运算符用于内置类型的对象的含义,只能用于自定义类型对象之间,

运算符重载

关键字:operator 相见:<高质量程序设计指南> P255 如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,有两个参数的运算符叫做二元运算符. 如果运算符被重载为类的成员函数,那么一元运算符没有参数(但是++和--运算符的后置版本除外),二元运算符只有右侧参数,因为对象自己成了左侧参数. 运算符重载的特殊性 如果重载为成员函数,则this对象发起对它的调用 如果重载为全局函数,则第一个参数发起对它的调用 禁止用户发明该语言运算符集合中不存在的运算符 除了函数调用运算符

C++ 运算符重载

C++中预定义的运算符的操作对象只能是基本数据类型,实际上,对于很多用户自定义类型,也需要有类似的运算操作.比如对象a和对象b, 那么 a+b 就需要用户自己定义它怎么相加,这时就用到了运算符重载. 运算符重载规则如下: ①. C++中的运算符除了少数几个之外,全部可以重载,而且只能重载C++中已有的运算符. ②. 重载之后运算符的优先级和结合性都不会改变. ③. 运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造.一般来说,重载的功能应当与原有功能相类似,不能改变原运算符的操作对

Kotlin中复合赋值(+=,-=,……)运算符重载

本篇建立在已经了解了kotlin中运算符重载的理念以及如何实现的基础上. 来我们首先写一个简单的类,然后重载运算符+,+=,-,-=这个几个运算符.代码如下: data class Point(var x: Int, var y: Int) { operator fun plus(point: Point): Point { return Point(this.x + point.x, this.y + point.y) } operator fun plusAssign(point: Poin

第十章 运算符重载

第十章 运算符重载 1.运算符重载的方法 (实质:函数重载) *一般格式: 函数类型名operator 运算符名称(参数表){函数体:} 2.运算符重载的规则 *不允许定义新的运算符 *允许重载的运算符 双目运算符 +(加法)  - (减法)  * (乘法) / (除法)   %(取模) 关系运算符 ==(等于) != (不等)  <   >   <=   >= 逻辑运算符 ||(或)   && (与)  !(非) 单目运算符 + (正)  -(负)   *(指针)

C++运算符重载的妙用

运算符重载(Operator overloading)是C++重要特性之中的一个,本文通过列举标准库中的运算符重载实例,展示运算符重载在C++里的妙用.详细包含重载operator<<,operator>>支持cin,cout输入输出.重载operator[],实现下标运算.重载operator+=实现元素追加:重载operator()实现函数调用.假设你对C++的运算符重载掌握的游刃有余.那就无需继续往下看了. 运算符重载带来的优点就是--让代码变得简洁.以下将展示几个标准库因使

网易云课堂_C++开发入门到精通_章节4:运算符重载

课时23运算符重载 运算符重载 重载赋值运算符 Person& Person::operator=(const Person& other) { //检查自赋值 if (this == &other) { return *this; } //释放原有的内存资源 delete[]m_data; int length = strlen(other.m_data); m_data = new char[length + 1]; strcpy(m_data, other.m_data);

关于c++的运算符重载那些事

搞c++有一段时间了,今天突然要重载一个运算符,发现自己有点忘了,遂查查资料做一下c++运算符重载的小总结. 一.何为运算符重载 运算符的重载是c++语言特有的,java什么的是没有运算符重载的,所以运算符重载在笔试面试中有可能成为c++的高频考点.运算符重载就是重新定义运算符的意义,如常用的+,-,×,÷都是可以重载的.运算符重载使用的是关键字operator,表现形式是:                                                            

C++:运算符重载函数之&quot;++&quot;、&quot;--&quot;、&quot;[ ]&quot;的应用

5.2.5 "++"和"--"的重载 对于前缀方式++ob,可以用运算符函数重载为: ob.operator++() //成员函数重载 或 operator++(X &ob) //友元函数重载,其中ob为类X的对象的引用 对于后缀方式++ob,可以用运算符函数重载为: ob.operator++(int) //成员函数重载 或 operator++(X &ob,int) //友元函数重载,其中ob为类X的对象的引用 调用时,参数int一般被传递给值0