C++学习31 重载=(赋值运算符)

和普通变量一样,对象之间也可以相互赋值。赋值运算符“=”可以用来将一个对象拷贝给另一个已经存在的对象。对象之间的赋值是将成员变量依次拷贝,而不是将整个对象的内存按位拷贝。

对象之间的赋值:

#include <iostream>
using namespace std;
class Demo{
private:
    int a;
    int b;
public:
    Demo(): a(0), b(0){ }
    Demo(int a, int b): a(a), b(b){ }
    void display(){ cout<<a<<", "<<b<<endl; }
};
int main(){
    Demo obj1, obj2(10, 20);
    obj1 = obj2;  //对象之间的赋值
    obj1.display();
    return 0;
}

一般情况下,默认的“=”就能满足我们的需求,但是当一个类中包含指针类型的成员变量时,可能会带来问题。请看下面的代码:

#include <iostream>
using namespace std;
class Book{
private:
    double price;  //书的价格
    int *bookmark;  //书签
    int num;  //书签的数量
public:
    Book(): price(0.0), bookmark(NULL), num(0){}
    Book(double, int*, int);
    void setBookmark(int, int);  //修改书签
    void display();
};
Book::Book(double price, int *bm, int num): price(price), num(num){
    int *bmTemp = new int[num];
    for(int i=0; i<num; i++){
        bmTemp[i] = bm[i];
    }
    this->bookmark = bmTemp;
}
void Book::setBookmark(int page, int index){
    if(index>=num-1){
        cout<<"Out of bound!"<<endl;
    }else{
        bookmark[index] = page;
    }
}
void Book::display(){
    cout<<"price: "<<price<<endl;
    cout<<"bookmarks: ";
    for(int i=0; i<num; i++){
        if(i==num-1){
            cout<<bookmark[i]<<endl;
        }else{
            cout<<bookmark[i]<<", ";
        }
    }
}
int main(){
    int bookmark[] = { 1, 49, 56, 290 };
    Book java, cpp(68.5, bookmark, 4);
    cpp.display();
    java = cpp;  //对象之间赋值
    java.setBookmark(100, 2);
    cpp.display();
    return 0;
}

这段代码定义了一个 Book 类,表示一本书,书有价格,也有书签。书签是我们所标记的页码,这些页码中往往包含重要的知识点,记录下这些页码能够方便以后查阅。书签可以有多个,所以需要将它放在 int 型的数组中。setBookmark() 函数用来修改某个书签,display() 函数用来展示书签和价格。

Book 类的构造函数中不是直接接收参数的值,而是根据参数所指向的数组,再创建一个新的数组。这样做的好处是对象有属于自己的数组,在其他地方修改实参所指向的数组不会影响该数组,能够很好的隔离。

在 main() 函数中,我们创建了两个对象 java 和 cpp,并用 cpp 给 java 赋值。两次调用 display() 的结果不同表明,调用 java 对象的 setBookmark( ) 函数影响到了 cpp 对象。这是因为,执行java = cpp;语句时会将 cpp.bookmark 的值复制给 java.bookmark,不同对象的成员变量指向同一个数组,当然会相互影响。

要解决这个问题,就需要重载赋值运算符,如下所示:

Book & Book::operator=(const Book &b){
    if( this != &b){
        this->price = b.price;
        this->num = b.num;
        //为bookmark赋值
        int *bmTemp = new int[b.num];
        for(int i=0; i<b.num; i++){
            bmTemp[i] = b.bookmark[i];
        }
        this->bookmark = bmTemp;
    }
    return *this;
}

将这个函数放入 Book 类中,再执行java = cpp;语句时,会转换为:

java.operator=(cpp);

在函数体中,this 就指向 java 对象。这样 java 对象也会拥有属于自己的数组,两个对象之间不会再相会影响。

可以发现,重载赋值运算符时,函数的参数和返回值类型都必须是对象的引用。以 Book 类为例来说,赋值运算符重载函数一般有两种原型:

Book & operator=( Book &b );
Book & operator=( const Book &b );

返回值和参数都是 Book 类对象的引用。下面一种原型则规定在赋值时不能修改原来的对象。

赋值运算符重载函数除了能有对象引用这样的参数之外,也能有其它参数。但是其它参数必须给出默认值。如下所示:

Book & operator=(const Book &b, a = 10);
时间: 2024-10-10 21:58:02

C++学习31 重载=(赋值运算符)的相关文章

没有躲过的坑--重载赋值运算符的自我赋值

C++中有个很重要的事情,就是对于类重载赋值运算符,而达到我们想要的结果. 先看看这几行代码: //Window 是一个类 Window w; w = w; // 再傻的人也不会这么干 w[i] = w[j]; // 这个情况偶尔会发生 作为一个优秀的工程师,就要考虑到任何可能的情况. 看一段更加完整的代码: class ScrollBar {}; class Window { ScrollBar *sb; public: Window(ScrollBar *s) : sb(s) {} Wind

重载赋值运算符 &amp;&amp; 对象

class CMessage { private: char * m_pMessage; public: void showIt()const { cout << m_pMessage << endl; } //构造函数 CMessage(const char* text="Default message") { cout << "Constructor difinition" << endl; size_t leng

拷贝构造函数(三)——重载赋值运算符

拷贝构造函数(一)--哲学三连:http://www.cnblogs.com/tenjl-exv/p/8017814.html 拷贝构造函数(二)--深拷贝与浅拷贝:http://www.cnblogs.com/tenjl-exv/p/8017909.html 拷贝构造函数(三)--重载赋值运算符:http://www.cnblogs.com/tenjl-exv/p/8017983.html 关于拷贝函数中的赋值操作符重载  以下讨论中将用到的例子: 1 class CExample 2 { 3

python学习31(面向对象)

类的两种类型:经典类:class Person():#没有继承objectPass 新式类:class Person(object):#继承objectpass 面向对象技术简介类(Class):用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例.类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外.类变量通常不作为实例变量使用.数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据.方法重写:如果从父类继承的方法不

第九章:重载赋值运算符中需要注意的两个问题

前言 如果系统自动生成的赋值运算符重载函数不合乎你的要求,那么就应当定制自己的赋值运算符. 然而,定制赋值运算符有两点是非常值得注意的,本文将讲解这两点,让你写出更优质的 =运算符. 第一点:请返回 reference to *this 我们经常使用如 "a=b=c=1" 这种形式的连锁赋值语句,而重载的赋值运算符自然也应当能够这样使用. 因此,在重载运算符函数末尾请写上如这样的语句 return *this; 除了赋值运算符,+=,-=这样的赋值运算符同样需要这样做. 第二点:处理好

重载赋值运算符中需要注意的两个问题

前言 如果系统自动生成的赋值运算符重载函数不合乎你的要求,那么就应当定制自己的赋值运算符. 然而,定制赋值运算符有两点是非常值得注意的,本文将讲解这两点,让你写出更优质的 =运算符. 第一点:请返回 reference to *this 我们经常使用如 "a=b=c=1" 这种形式的连锁赋值语句,而重载的赋值运算符自然也应当能够这样使用. 因此,在重载运算符函数末尾请写上如这样的语句 return *this; 除了赋值运算符,+=,-=这样的赋值运算符同样需要这样做. 第二点:处理好

C++学习28 重载&gt;&gt;和&lt;&lt;(输入输出运算符)

在C++中,系统已经对左移运算符“<<”和右移运算符“>>”分别进行了重载,使其能够用于输入输出,但是输入输出的处理对象只能是系统内建的数据类型.系统重载这两个运算符是以系统类成员函数的形式进行的,因此cout<< var语句可以理解为: cout.operator<<( var ) 如果我们自己定义了一种新的数据类型,需要用输入输出运算符去处理,那么就要重载.本节以前面的 complex 类为例说明输入输出运算符的重载. 重载输入运算符>> 下

C++学习之重载运算符1

C++除可重载函数之后,还允许定义已有的运算符,这样通过运算符重载可像处理数据使用它们. 先来个代码 1 #include<iostream> 2 using namespace std; 3 4 class num 5 { 6 public: 7 num(){n=1;} 8 ~num(){} 9 int get() const{return n;} 10 void set(int x){n=x;} 11 private: 12 int n; 13 }; 14 15 int main() 16

C++学习30 重载++和--(自增自减运算符)

自增“++”和自减“--”都是一元运算符,它的前置形式和后置形式都可以被重载.请看下面的例子: #include <iostream> #include <iomanip> using namespace std; class stopwatch{ //秒表 private: int min; //分钟 int sec; //秒钟 public: stopwatch(): min(0), sec(0){ } void setzero(){ min = 0; sec = 0; } s