C++学习之路 day6

Day6知识点:

1.  在运算符重载时尽量遵循原有默认的规则,如以下代码

int a , b , c;
(a + b) = c;      //是错误的

而在运算符重载中:

Complex Complex::operator+(Complex& another)
{
    Complex t;
    t._x = _x + another._x;
    t._y = _y + another._y;
    return t;
}
Complex c1(1,2) ,c2(2,3);
(c1 + c2) = c;	              //是正确的,但不遵循默认语法规则

2. C++不允许用户自定义新的运算符,只能对已有的C++运算符进行重载


C++允许重载的运算符:


C++不允许重载的运算符只有个:


3.  对于双目运算符

重载为成员(即成员函数)的话,需要一个参数,重载为友元(即全局函数)的时候需要两个参数

const Complex operator+(Complex& another);
friend Complex operator+(Complex& a,Complex& b);


   对于单目运算符

   重载为成员的话,不需要参数,重载为友元时需要一个参数。

   三目运算符无法重载。

4.

若函数重载为

void Complex::operator+=(const Complex &another)
{
    this->_x += another._x;
    this->_y += another._y;
}

x +=y;        //可行
x += y += z;  //不可行,不能用做右值,所以应有返回值

若函数重载为

Complex Complex::operator+=(const Complex &another)
{
    this->_x += another._x;
this->_y += another._y;
return *this;
}
x +=y;        //可行
x += y += z;	//可行
(x += y) += z;// 不可行,不能用作左值,所以应返回引用

最终确认版本为:

Complex& Complex::operator+=(const Complex &another)
{
    this->_x += another._x;
    this->_y += another._y;
    return *this;
}
逐步迭代,尽量使语法规则接近自然语言。

例1.+操作符重载

#include <iostream>

using namespace std;

class Complex
{
public:
    Complex(float x = 0,float y = 0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<" , "<<_y<<")"<<endl;
    }
//    friend Complex operator+(Complex& a,Complex& b);
    const Complex operator+(Complex& another);
private:
    float _x;
    float _y;
};

//Complex operator+(Complex& a,Complex& b)
//{
//    Complex t;
//    t._x = a._x + b._x;
//    t._y = a._y + b._y;
//    return t;
//}

const Complex Complex::operator+(Complex& another)
{
    Complex t;
    t._x = _x + another._x;
    t._y = _y + another._y;
    return t;
}

int main()
{
    Complex c1(1,2) ,c2(2,3);

//    Complex c = c1 + c2;
//    Complex c = operator+(c1,c2);
    Complex c = c1.operator+(c2);
    c1.dis();
    c2.dis();
    c.dis();

//    (c1 + c2) = c;

    return 0;
}

例2.+=操作符重载

#include <iostream>

using namespace std;

class Complex
{
public:
    Complex(float x = 0,float y = 0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<" , "<<_y<<")"<<endl;
    }

    Complex& operator+=(const Complex &another);
private:
    float _x;
    float _y;
};

Complex& Complex::operator+=(const Complex &another)
{
    this->_x += another._x;
    this->_y += another._y;
    return *this;
}



int main()
{
    int a = 10, b = 20, c = 30;

//    a += b;
//    b += c;

//    a += b += c;
    (a += b) += c;
    cout<<a<<endl;
    cout<<b<<endl;
    cout<<c<<endl;

    cout<<"--------------------------"<<endl;

    Complex x(10,0), y(20,0), z(30,0);

//    x += y;
//    y += z;

//    x += y += z;
    (x += y) += z;

    x.dis();
    y.dis();
    z.dis();


    return 0;
}


5.

1).单目运算符-的重载

   若重载函数为
 Complex operator-()
 {
     return Complex(-this->_x,-this->_y);
 }

则:

Complex c(1,1);
Complex t = -c;	//可行,符合常用规则
Complex t = -(-c);	  //可行,符合常用规则
Complex m(2,2);
-c = m;				  //可行,不符合常用规则

若将重载函数改为

 

const Complex operator-()
{
     return Complex(-this->_x,-this->_y);
 }


-c = m;	//不能通过
t = -(-c);	//也不能通过

因为-c调用时返回的const Complex,但是const类对象只能调用const成员函数

所以应改为:

 const Complex operator-()const
 {
        return Complex(-this->_x,-this->_y);
 }

-c = m;	//不能通过
t = -(-c);	//能通过

例3.单目操作符-(负号)重载

 
  

#include <iostream>

using namespace std;

class Complex
{
public:
    Complex(float x = 0,float y = 0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<" , "<<_y<<")"<<endl;
    }

    const Complex operator-()const
    {
        return Complex(-this->_x,-this->_y);
    }

private:
    float _x;
    float _y;
};

int main()
{
    int n = 5;
    cout<<n<<endl;
    cout<<-n<<endl;
    cout<<n<<endl;
    cout<<-(-n)<<endl;

//    -n = 30;  //   返回值不可以赋值,所以用const

    Complex c(1,1);

//    Complex t = -c;
    Complex t = -(-c);
//    Complex t(2,2);
//    -c = t;
    c.dis();
    t.dis();


    return 0;
}



2)双目运算符<<与>>的重载
   <<是双目运算符,左边是cout的类型ostream&,右边是Complex&类型,因为可以连续使用,所以返回值也为ostream&的类型,如果将operator<<()声明为成员函数的话,那么 cout.operator<<()是成立的,即但是operator并不是Complex类的成员函数,而是cout类的成员函数,所以只能声明为友元函数
    friend ostream& operator<<(ostream& os,const Complex& c)
    {
        cout<<"("<<c._x<<" , "<<c._y<<")"<<endl;
    }
同理,流输入运算符>>重载为
    friend istream& operator>>(istream& is,Complex& c)          //此处由于有数据流入c,所以不可加const         
    {
        is>>c._x>>c._y;
        return is;
    }
如若把流输入运算符在myString中重载,考虑到不能确定_str容量的大小,应该这样定义流输入运算符
istream& operator>>(iostream &is,myString &s)
{
    delete s._str;              //初始化时会new一份空间给它,所以需事先delete掉这份空间
    char buf[BUFSIZ];
    
    int len = strlen(buf);
    s._str = new char[len+1];
    strcpy(s._str,buf);
    return is;
}

例4.双目操作符<<与>>的重载

#include <iostream>

using namespace std;

class Complex
{
public:
    Complex(float x = 0,float y = 0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<" , "<<_y<<")"<<endl;
    }

    friend ostream& operator<<(ostream& os,const Complex& c)    //可移植性强
    {                                                           //把参数中的Complex修改后
        cout<<"("<<c._x<<" , "<<c._y<<")"<<endl;                //可直接移植到myString中声明
        return os;                                              //然后略微修改函数体即可
    }                                                           //
    friend istream& operator>>(istream& is,Complex& c)          //此处由于有数据流入c,所以不可加const
    {
        is>>c._x>>c._y;
        return is;
    }
private:
    float _x;
    float _y;
};

int main()
{
    Complex c(1,2);
//    c.dis;
    cin>>c;
    cout<<c<<endl;
    return 0;
}

例5.发送邮件作业

#include <iostream>

using namespace std;

class Mail;

class Sender
{
public:
    Sender(string s):_addr(s){}
    Sender operator <<(Mail& mail);

private:
    string _addr;

};

class Mail
{
public:
    Mail(string _t,string _c):_title(_t),_content(_c) {}
    friend Sender Sender:: operator <<(Mail& mail);
private:
    string _title;
    string _content;
};

Sender Sender::operator <<(Mail& mail)
{
    cout<<_addr<<endl;
    cout<<mail._title<<endl;
    cout<<mail._content<<endl;
    return *this;
}


int main()
{
    Sender sender("666666@163.com");
    Mail mail1("note","holiday 8/26-8/27");
    Mail mail2("note","cancel holiday.");
    sender<<mail1<<mail2;
    return 0;
}


6.在进行类型转换时不要混淆两种类型转换的方法
(float)5/8;                 //C中强制类型转化,正确
static_cast<float>(5)/8;    //C++中强制类型转化,正确
float(5)/8;                 //错误

7.类型转换构造器
      转换构造函数,本质上是一个构造函数,是只有一个参数的构造函数,作用:把其他类型显式转换为自身的类型,广泛运用于赋值,传参

class Point3D
{
public:

    Point3D(const Point2D &p2)
    {
        this->_x = p2._x;
        this->_y = p2._y;
        this->_z = 0;
    }

};


    Point2D p2(1,2);
    Point3D p3(3,4,5);
    p3 = p2;            //转换构造函数赋值,先把隐式p2升级为3D类型,然后发生的是一种赋值,利用构造函数实现
    convert(p2);        //转换构造函数传参


8.explicit关键字
若在转换构造函数前加上explict关键字,则在转换过程中不能隐式转换,只能显示转换
    p3 = (Point3D)p2;            
    convert((Point3D)p2);    

9.类型转化操作符函数


作用:把自身类型隐式或显式转换为其他类型,转换函数无参数无返回
class Point3D
{
public:
    operator Point2D(void)
    {
        return Point2D(this->_x,this->_y);  //将3D转换成3D,特例,不用写返回类型
    }
};
Point2D p2(p3);

10.函数运算符()的重载
     仿函数,就是使一个类使用看上去像一个函数
class Pow
{
public:
    Pow() {}
    int operator ()(int i)
    {
        return i * i;
    }
};


int main()
{
    Pow pow;
    int i = 4;
    cout << pow(i)<< endl;  //按常理来说应该是pow()i,系统为了美观变成pow(i)
    return 0;
}

11.堆内存操作符的重载(new delete)
格式如下
重点:可以在new中实现自我的早期定制而不用使用构造函数,详细内容见例6。

例6. 堆内存运算符的重载

#include <iostream>
#include <string.h>

using namespace std;

class A
{
public:
    A()
    {
        cout<<"A()"<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<endl;
    }
    void func()
    {
        cout<<"void func()"<<endl;
    }

    void* operator new(size_t size)
    {
        cout<<"size = "<<size<<endl;
        cout<<"void* operator new(size_t size)"<<endl;
        void *p = malloc(size);
        memset(p,0,size);

        return p;
    }

    void operator delete(void *p)
    {
        cout<<"void operator delete(void *p)"<<endl;
        free(p);
    }

    void *operator new[](size_t size)
    {
        cout<<"size = "<<size<<endl;
        cout<<"void *operator new[](size_t size)"<<endl;

        void *p = malloc(size);
        memset(p,0,size);
        ((A*)p)->data = 100;        //可以实现自我早期定制,不用使用构造器
        return p;
    }

    void operator delete[](void *p)
    {
        cout<<"void operator delete[](void *p)"<<endl;

        free(p);
    }

    double data;

};



int main()
{
    A* p = new A;
    p->func();
    cout<<p->data<<endl;

    delete p;

//    A* p = new A[5];
//    p->func();

//    delete []p;
//    int *p = new int;
    return 0;
}



12.智能指针的重载
智能指针:
    auto_ptr<A> ptr(new A);        //auto_ptr 类模板    auto_ptr<A>模板类
要实现智能指针的重载,建立一个类,利用类对象成员退出栈空间的析构函数来实现自动delete
#include <iostream>
#include <string.h>
#include <memory>

using namespace std;

class A
{
public:
    A()
    {
        cout<<"A()"<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<endl;
    }

    void func()
    {
        cout<<"void func()"<<endl;
    }


};


class Smt
{
public:
    Smt(A *p)
    {
        ptr = p;
    }
    ~Smt()
    {
        delete ptr;
    }

    A*& operator->()
    {
        return ptr;
    }
    A& operator*()
    {
        return *ptr;
    }

    A *ptr;
};

void foo()
{
//    auto_ptr<A> ptr(new A);        //auto_ptr 类模板    auto_ptr<A>模板类
                                   //new A被ptr托管以后,不需要再关心delete的问题。delete在ptr离开其栈空间时发生
//    ptr->func();
//    (*ptr).func();
    Smt smt(new A);                  //模拟智能指针自动delete
    (*smt).func();
//    smt->func();
//    (smt.ptr)->func();
}

int main()
{
    foo();
    return 0;
}

13.++的重载
前置++的重载
在默认++的运算中有以下计算规则
int main()
{
    int a = 100;
    int b = ++a;
    cout<<a<<" "<<b<<endl;
    ++++a;
    cout<<a<<endl;
}

所以可得重载函数为
Complex& Complex::operator ++()
{
    this->_x++;
    this->_y++;
    return *this;
}

后置++的重载
计算规则
int main()
{
    int a = 100;        //能通过
    int b = a++;        //能通过
    a++++;              //无法通过
    cout<<a<<" "<<b<<endl;
}

由于a++++无法通过,所以返回值类型为const型,因为const类型无法调用非const函数
在选择返回类型是否为引用时,原则是能使用引用尽量使用引用。
为了区分前++和后++,在后++的重载函数调用参数中加 int ,如果为全局的,函数调用参数为(complex &,int)















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值