程序设计与算法三第四周笔记

运算符重载:

运算符重载的形式  

  1. 运算符重载的实质是函数重载 
  2. 可以重载为普通函数,也可以重载为成员函数 
  3. 把含运算符的表达式转换成对运算符函数的调用。 
  4. 把运算符的操作数转换成运算符函数的参数。 
  5. 运算符被多次重载时,根据实参的类型决定调用哪个运算符函数。

运算符重载的形式API 

返回值类型操作运算符(形参表){......} 

class Complex
{
public:
    double real,imag;
    Complex( double r = 0.0, double i= 0.0 ):real(r),imag(i) { }
    Complex operator-(const Complex & c);
};
Complex operator+( const Complex & a, const Complex & b)//普通函数定义在Complex外面
{
    return Complex( a.real+b.real,a.imag+b.imag); //返回一个临时对象
}
Complex Complex::operator-(const Complex & c)
{
    return Complex(real - c.real, imag - c.imag); //返回一个临时对象
}
重载为成员函数时,参数个数为运算符目数减一。
重载为普通函数时,参数个数为运算符目数。
int main()
{
    Complex a(4,4),b(1,1),c;
    c = a + b; //等价于c=operator+(a,b);
    cout << c.real << "," << c.imag << endl;
    cout << (a-b).real << "," << (a-b).imag << endl;
    //a-b等价于a.operator-(b)
    return 0;
}
输出:
5,5
3,3
c = a + b; 等价于c=operator+(a,b);
a-b 等价于a.operator-(b)

上述代码对比友元函数:

class Complex
{
    double real,imag;
public:
    Complex( double r, double i):real(r),imag(i){ };
    Complex operator+( double r );   
    friend Complex operator+ (double r,const Complex & c)//友元函数在函数体内部
    { //能解释 5+c//因为普通函数不能访问私有成员,所以,需要将运算符 + 重载为友元。
        return Complex( c.real + r, c.imag);
    }
};
Complex Complex::operator+( double r )
{ //能解释 c+5
    return Complex(real + r,imag);
}

浅拷贝和深拷贝:

class String {
private:
    char * str;
public:
    String ():str(new char[1]) { str[0] = 0;}
    String & operator = (const char * s){
        delete [] str;
        str = new char[strlen(s)+1];
        strcpy( str, s);
        return * this;
    }
    ~String( ) { delete [] str; }
}

问题:

  1. 如不定义自己的赋值运算符,那么S1 = S2实际上导致S1.str和S2.str指向同一地方。
  2. 如果S1对象消亡,分构函数将释放S1.str指向的空间,则S2消亡时还要释放一次,不妥。
  3. 另外,如果执行S1 =“other”;会导致S2.str指向的地方被删除
  4. 因此要在类的字符串里面添加成员函数:
String & operator = (const String & s) {
    delete [] str;
    str = new char[strlen( s.str)+1];
    strcpy( str,s.str);
    return * this;
}

流插入运算符的重载原理:

ostream& ostream :: operator <<(int n){

     ...... //输出n的代码

     返回*这个; }

ostream& ostream :: operator <<(const char * s){

     ...... //输出s的代码

     返回*这个; }

流插入运算符的重载cout << 5 <<“this”; 本质上的函数调用的形式是什么?cout.operator <<(5).operator <<(“this”); 流插入运算

流插入运算符的重载实例:

class CStudent{
public: 
    int nAge;
};
int main(){
    CStudent s ;
    s.nAge = 5;
    cout << s <<"hello";
    return 0;
}
//流插入运算符的重载,,全局函数
ostream & operator<<( ostream & o,const CStudent & s){
        o << s.nAge ;
        return o;
}

实例:

数类的对象,现在希望写“cout << c;”,就能以“a + bi”的形式输出c的值,

写“cin”c;“,就能从键盘接受”a + bi“形式的输入,并且使得c.real = a,c.imag = b。

例题
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Complex {
    double real,imag;
public:
    Complex( double r=0, double i=0):real(r),imag(i){ };
    friend ostream & operator<<( ostream & os,const Complex & c);
    friend istream & operator>>( istream & is,Complex & c);
};
ostream & operator<<( ostream & os,const Complex & c)
{
    os << c.real << "+" << c.imag << "i"; //以"a+bi"的形式输出
    return os;
} 
istream & operator>>( istream & is,Complex & c)
{
    string s;
    is >> s; //将"a+bi"作为字符串读入, “a+bi” 中间不能有空格
    int pos = s.find("+",0);
    string sTmp = s.substr(0,pos); //分离出代表实部的字符串
    c.real = atof(sTmp.c_str()); //atof库函数能将const char*指针指向的内容转换成 float
    sTmp = s.substr(pos+1, s.length()-pos-2); //分离出代表虚部的字符串
    c.imag = atof(sTmp.c_str());
    return is;
}
int main()
{
    Complex c;
    int n;
    cin >> c >> n;
    cout << c << "," << n;
    return 0;
}
运行结果可以如下:
13.2+133i 87↙
13.2+133i, 87

重载类型转换运算符:

#include <iostream>
using namespace std;
class Complex
{
    double real,imag;
public:
    Complex(double r=0,double i=0):real(r),imag(i) { };
    operator double () { return real; }
//重载强制类型转换运算符 double,返回值其实就是double类型,类型转换运算符重载不写返回值类型
};
int main()
{
    Complex c(1.2,3.4);
    cout << (double)c << endl; //输出 1.2
    double n = 2 + c; //等价于 double n=2+c.operator double()
    cout << n; //输出 3.2
}

自增,自减运算符重载:

C++中存在(++a)=1,不存在(a++)=1

前置运算符还是后置运算符,C++规定: 

自增运算符++、自减运算符--有前置/后置之分,为了区分所重载的是前 置运算符还是后置运算符,C++规定:

前置运算符作为一元运算符重载 重载为成员函数:

重载为成员函数:

T & operator++(); //因为原始定义++a返回的是&a,故返回T&和原始++保持一致

T & operator--();

重载为全局函数:

T1 & operator++(T2);

T1 & operator—(T2);

后置运算符作为二元运算符重载,多写一个没用的参数:

重载为成员函数:

T operator++(int); T operator--(int);

重载为全局函数:

T1 operator++(T2,int ); T1 operator—( T2,int);

但是在没有后置运算符重载而有前置重载的情况下, 在vs中,obj++ 也调用前置重载,而dev则令 obj ++编译出错

int main()
{
    CDemo d(5);
    cout << (d++ ) << ","; //等价于 d.operator++(0);
    cout << d << ",";
    cout << (++d) << ","; //等价于 d.operator++();
    cout << d << endl;
    cout << (d-- ) << ","; //等价于 operator--(d,0);
    cout << d << ",";
    cout << (--d) << ","; //等价于 operator--(d);
    cout << d << endl;
    return 0;
}
输出结果:
5,6,7,7
7,6,5,5
如何编写 CDemo
class CDemo {
private :
int n;
public:
    CDemo(int i=0):n(i) { }
    CDemo & operator++(); //用于前置形式,因为原始定义++a返回的是&a,和原始++保持一致
    CDemo operator++( int ); //用于后置形式
    operator int ( ) { return n; }
    friend CDemo & operator--(CDemo & );
    friend CDemo operator--(CDemo & ,int);
};
CDemo & CDemo::operator++()
{ //前置 ++
    n ++;
    return * this;
} // ++s即为: s.operator++();
CDemo CDemo::operator++( int k )
{ //后置 ++
    CDemo tmp(*this); //记录修改前的对象
    n ++;
    return tmp; //返回修改前的对象
} // s++即为: s.operator++(0);
CDemo & operator--(CDemo & d)
{//前置--
    d.n--;
    return d;
} //--s即为: operator--(s);
CDemo operator--(CDemo & d,int)
{//后置--
    CDemo tmp(d);
    d.n --;
    return tmp;
} //s--即为: operator--(s, 0);

这里,int作为一个类型强制转换运算符被重载,此后
Demo s;
(int)s; //等效于s.int();


类型强制转换运算符被重载时不能写返回值类型,其实际上报道查看值类型就
的英文该类型强制转换运算符代表的类型

由上述代码得出前置++, - 速度由于后置++, -

 

运算符重载的注意事项:

  1. 1. C ++不允许定义新的运算符;
  2.  重载后运算符的含义应该符合日常习惯; complex_a + complex_b; word_a> word_b; date_b = date_a + n
  3. 运算符重载不改变运算符的优先级;
  4. 以下运算符不能被重载:“”“*”,“::”,“?:”,的sizeof;
  5. 重载运算符(),[], - >或者赋值运算符=时,运算符重载函数必须声明为类的成员函数

猜你喜欢

转载自blog.csdn.net/qq_31647835/article/details/81213509
今日推荐