第四周学习

来源:互联网 发布:九珠数学算法视频教程 编辑:程序博客网 时间:2024/06/15 14:00

4.1运算符重载

  • 对已有的运算符赋予多重的含义
  • 使同一运算符作用于不同类型的数据时能够有不同的功能
  • 扩展c++中运算符的功能
    5+4=9
    5+6i+7+3i=12+9i
  • 运算符重载的实质是函数的重载
    返回值类型 operator 运算符(形参表){…}
class complex{public:    complex(int a,int b){real=a;imag=b;}    int real,imag;    complex operator+(const complex& a){    return complex(real+a.real,imag+a.imag)}//重载为成员函数的时候只需要一个参量。};    complex::complex operator+(const complex &a,const complex &b){    return complex(a.real+b.real,a.imag+b.imag)}//重载为普通函数的时候为两个参量,为运算符目数。两者是等价的

4.2赋值运算符 = 的重载

  • 可以将赋值运算符重载为想要的功能,比如把int赋值给complex等。
  • 赋值运算符 = 只能重载为成员函数

e.g 自己的string类

#include <iostream>using namespace std;class String{private:    char *str;public:    String():str(NULL){}    const char *c_str(){return str;}    char *operator =(const char *s);    ~String();    String(const char *s1){        str=new char[strlen(s1)+1];        strcpy(str,s1);//用*char可以完成,strcpy做的是拷贝的工作,将后者拷贝给前者    }};char *String::operator=(const char *s){    if(str) delete[] str;    if(s){        str=new char[strlen(s)+1];        strcpy(str,s);    }else{        str=NULL;    }    return str;}String::~String(){    if(str) delete[] str;}int main(){    String s;    s="good sdf";//为了满足这个等号,需要对赋值运算符进行重载    String s2="hello lsidfh";    cout<<s.c_str()<<endl;//s.c_str()目的是返回一个*char    cout<<s2.c_str()<<endl;    return 0;}

深拷贝和浅拷贝

  • 当自己不定义复制构造函数的时候,系统会自动生成一个复制构造函数,将原有的内容一字节一字节的拷贝给新的对象。
  • 但有时候,我们并不希望如此,当对象的成员变量有指针的时候,会出现以下情况:a对象和b对象的指针内容在相同的内存空间中,则可以通过b对象的成员指针改变a对象的内容,这不是我们想要的
  • 于是有了深拷贝,需要对新对象的指针对象开辟新的空间,并复制原来对象的内容进去,这样,虽然先后两个对象的指针变量指的内容是一致的,但在内存空间中是不同的位置,不会相互影响

4.3运算符重载为友元函数

  • 成员函数不能满足使用需求,而普通函数不能访问类私有成员
    例如,现有一个类名叫complex,要实现complex+5,可以通过成员函数的重载实现,这句话等于complex.+(5),但若想要实现5+complex,需要对整体的 + 进行重载,就不能是成员函数,而是要普通函数,而普通函数不能访问类的私有成员,所以只能是友元函数才可以。
class complex{private:    double real,imag;public:    complex(double r, double i):real(r),imag(i){};    complex operator+ (double r){        return complex(real+r,imag);    }//对于后置的加号,只要通过成员函数即可实现};int main(){    complex a(2,3),b(1,1);    b=a+5;//完成后置加号的重载    return 0;}

对于前置加号,只能通过重载为友元实现

class complex{private:    double real,imag;public:    complex(double r, double i):real(r),imag(i){};    complex operator+ (double r){        return complex(real+r,imag);    }friend complex operator+ (double r,const complex& c);//申明友元函数};complex operator+ (double r,const complex& c){    return complex(c.real+r,c.imag);}//定义普通函数operator+int main(){    complex a(2,3),b(1,1);    b=a+5;    b=5+a;    return 0;}

4.4 e.g.可变长整形数组

  • 需求,编写一个程序,完成动态可变数组,需要多大的数组,就可以扩大成为那么大的。
    需要实现的c++主程序:
int main(){    CArray a;//创建一个可变数组对象    for(int i=0;i<5;++i){        a.push_back(i);//支持push_back函数加入新的元素    }    CArray a2,a3;    a2=a;//可以通过等号进行深拷贝    for(int i=0;i<a.length();++i){        cout<<a2[i]<<" ";//支持流输出运算符    }    a2=a3;    for(int i=0;i<a2.length();++i){        cout<<a2[i]<<" ";    }    cout<<endl;    a[3]=100;//支持直接调用    CArray a4(a);//支持这样构造    for(int i=0;i<a4.length();++i){        cout<<a4[i]<<" ";    }    return 0;}

实现:

#include <iostream>using namespace std;class CArray{public:    int *a1;    int size;    void push_back(const int &a){//将新的地址加上新的元素赋值给旧的        int *p2;        int *p1;        int *a3;        a3=a1;        p1=new int[size+1];        p2=p1;        for(int i=0;i<size;++i){            *p2=*a3;            ++p2;            ++a3;        }        *p2=a;        ++size;        a1=p1;        delete p1;    }    CArray (CArray &a){//深拷贝        size=a.size;        int *p1;        int *p2;        p1=new int[size];        p2=p1;        for(int i=0;i<size;++i){            *p2=*(a.a1+i);            ++p2;        }        a1=p1;        delete [] p1;    }    CArray(){size=0;}    int length(){return size;}    int & operator[](int i){//实现[]调用        return a1[i];    }    ~CArray(){//检查是否还有未删除的指针    if(a1){delete [] a1;}    }};int main(){    CArray a;    for(int i=0;i<5;++i){        a.push_back(i);    }    CArray a2,a3;    a2=a;    for(int i=0;i<a.length();++i){        cout<<a2[i]<<" ";    }    a2=a3;    for(int i=0;i<a2.length();++i){        cout<<a2[i]<<" ";    }    cout<<endl;    a[3]=100;    CArray a4(a);    for(int i=0;i<a4.length();++i){        cout<<a4[i]<<" ";    }    return 0;}

4.5流插入运算符和流提取运算符的重载

  • 若想输出或者输入某个类,就要对其进行重载,重载为ostream/istream的引用
    e.g.
    假设c是complex复数类的对象,现在希望写 “cout<
#include <iostream>using namespace std;class Complex{private:    double real,imag;public:Complex(int a=0,int b=0):real(a),imag(b){}friend ostream &operator<<(ostream & o,const Complex &s);friend istream &operator>>(istream & o,Complex &s);//申明友元的重载};ostream &operator<<(ostream & o,const Complex &s){    o<<s.real<<"+"<<s.imag<<"i";    return o;}istream &operator>>(istream & o,Complex &c){    string s;    o>>s;    int pos=s.find("+",0);    string stmp=s.substr(0,pos);    c.real=atof(stmp.c_str());    stmp=s.substr(pos+1,s.length()-pos-2);    c.imag=atof(stmp.c_str());    return o;}int main(){    Complex c;    int n;    cin>>c>>n;    cout<<c<<","<<n;    return 0;}

4.6自加/自减运算符的重载

  • 自加自减运算符分前置后置分别进行重载
  • 前置运算符作为一元运算符重载
  • 重载为成员函数时,变量减一

    • T operator++();
    • T operator–();
  • 重载为全局函数,变量为一

    • T operator++(T);
    • T operator–(T);
  • 后置运算符作为二元运算符重载

  • 重载为成员函数时候,变量减一,多写一个参数,具体无意义
    • T operator++(int)
    • T operator–(int)
  • 重载为全局函数的时候,有两个变量
    • T operator++(T, int)
    • T operator–(T, int)
#include <iostream>using namespace std;class cdemo{private:    int a;public:    friend ostream &operator<<(ostream &o,cdemo &s);    cdemo(int i):a(i){}    cdemo &operator ++(){//前置,不需要加变量        a++;        return *this;    }    cdemo &operator ++(int){//后置,需要加个变量        cdemo tmp(*this);        a++;        return tmp;    }};ostream &operator<<(ostream &o,cdemo &s){//流输出重载    o<<s.a;    return o;}int main(){    cdemo d(5);    cout<<(d++)<<",";    cout<<d<<",",    cout<<(++d)<<",";    cout<<d<<endl;    cout<<(d--)<<","    cout<<d<<",";    cout<<(--d)<<","    cout<<d<<",";    cout<<d<<endl;    return 0;}