C++从入门到精通 (5) (适合C入门后C++进阶) 连载!!!

今天知识点不多 但代码量不少知识点也比较重要 希望大佬们坚持住!!!

目录

🌹operator 重载运算符

🌷概述

🌷+号运算符重载

🌷<<运算符重载

🌷重载>>运算符(输入)

🌷==运算

🌷++前置后置递增运算符重载

🌷前置--和后置--

🌷定义一个智能指针 指针运算符重载 (了解)

🌷=赋值运算符的重载

🌷[]数组运算符重拷贝

🌷仿函数重载

🌹项目:利用类和重载的知识点 写一个自己的string类


operator 重载运算符

前面学习过基本运算符,重载则是在已有运算符的基础上重新写一套运算符的实现

应用场景:当我们使用自定义对象进行运算符操作时,相同无法识别。需要重载

例如:打印对象----cout

概述

重载函数: operator

操作步骤:

1.考虑运算符有多少参数个数;确定多少个,则重载时需要写多少个

2.运算符函数的左边是自定义对象还是其他类型

左边:是其他 只能全局函数实现 (必须使用全局友元)

左边:自定义对象

可以用全局友元(参数个数 和 运算符对象的个数一致)

成员函数(参数可以少一个) (推荐

+号运算符重载

自定义类型运算时 系统一般不会提供相应的运算符 所以需要用户重载

class Person
{
public:
    Person(){};
    Person(int a,int b):m_A(a),m_B(b){}
    int m_A;
    int m_B;
    //类内函数重载 +
    // Person operator +(const Person& p)
    // {
        // Person tmp;
        // tmp.m_A = m_A + p.m_A;
        // tmp.m_B = m_B + p.m_B;
        // return tmp;
    // }
    
};

//类外函数重载 +
Person operator+ (const Person& p1,const Person& p2)
    {
        Person tmp;
        tmp.m_A = p1.m_A + p2.m_A;    
        tmp.m_B = p1.m_B + p2.m_B;
        return tmp;
    }
//运算符重载的函数重载
Person operator+ (const Person& p1,const int num)
{
    Person tmp;
    tmp.m_A = p1.m_A + num;    
    tmp.m_B = p1.m_B + num;
        return tmp;
}

void test_01()
{
    Person p1(10,20);
    Person p2(5,5);
    Person p3 = p1 + p2;    //自定义类型运算时 系统一般不会提供相应的运算符 所以需要用户重载
    cout<<"p1.m_A = "<<p1.m_A<<endl;
    cout<<"p3.m_A = "<<p3.m_A<<endl;
    cout<<"p3.m_B = "<<p3.m_B<<endl;
    p3 = p1 + 10;    //测试运算符重载可以发生函数重载吗
    cout<<"p3.m_A + 10 = "<<p3.m_A<<endl;
    cout<<"p3.m_B + 10 = "<<p3.m_B<<endl;
}

<<运算符重载

注意事项:cout的数据类型为:ostream

左移运算符只能在类外定义实现 (如果类内实现 无法实现cout在左边)如果想访问类内私有成员 可以将全局函数设为类的友元

class Person
{
public:
    Person(int a,int b)
    {
    this->m_A = a;
    this->m_B = b;
    }
    int m_A;
    int m_B;
};

ostream& operator <<(ostream& cout,const Person& p)
{
    cout<<p.m_A<<endl;
    cout<<p.m_B<<endl;
    return cout;
}

void test_01()
{
    Person p(10,20);
    cout<<p<<"ok"<<endl;    //错误  需要重载左移运算符
}

重载>>运算符(输入)

class Person{
    friend istream& operator >>(istream &cin,Person &ob);
private:
    string name;
    int age;
public:
    Person(){}
    Person(string name,int age){
        this->name = name;
        this->age  = age;
    }
};
istream& operator >>(istream &cin,Person &ob)
{
    cin>>ob.name>>ob.age;
    return cin;
}
void test02(){
    Person p2;
    cin>>p2;
    cout<<"打印对象:"<<p2<<endl;
}

==运算

class Person{
private:
    string name;
    int age;
public:
    Person(){}
    Person(string name,int age){
        this->name = name;
        this->age  = age;
    }
    bool operator ==(Person &ob)
    {
        return name==ob.name&&age==ob.age;  //比较属性的相等
    }
};
void test02(){
    //Person p("zs",12);
    //打印输出的本质:调的是operator(cout,变量)函数
    //cout<<p<<endl;  //系统不能输出自定义对象
    /*
    Person p2;
    cin>>p2;
    cout<<"打印对象:"<<p2<<endl;*/


    Person p4("ww",30);
    Person p3("ls",30);  //重载是都是转为属性的操作
    //cout<<"打印对象:"<<(p3+p3)<<endl;
    cout<<(p3==p4)<<endl;    //0
}

++前置后置递增运算符重载

注意:前置++正常定义 后置++需要在形参添加一个占位符来告诉编译器定义的为后置++

前置++返回的是引用 后置++返回的是值 (前置++比后置++效率更高 因为后置++会调用拷贝构造 创建新的数据)

class Person
{
public:
    Person(int age)
    {
        m_Age = age;
    }
    int m_Age;
    //前置++的重载
    Person& operator++()
    {
        this->m_Age++;
        return *this;
    }
    //后置++的重载
    Person operator++(int )    //int 占位符 后置++与前置++通过占位符区分
    {
        Person temp(0);
        temp.m_Age=this->m_Age;
        this->m_Age++;
        return temp;
    }
};

//左移运算符的重载
ostream& operator <<(ostream& cout,const Person& p)
{
    cout<<p.m_Age;
    return cout;
}

void test_01()
{
    Person p(18);
    cout<<"++p = "<<++p<<endl; //报错 需要前置++重载
    cout<<"p++ = "<<p++<<endl; //报错 需要后置++重载
    cout<<"p = "<<p<<endl;
}

前置--和后置--

自己动手写一下前置--和后置--吧😀

定义一个智能指针 指针运算符重载 (了解)

用途:托管new出来的对象的释放

设计一个智能类 内部维护new出来的person类 在析构的时候释放堆区new出来的person对象

class Person
{
public:
    Person(int age)
    {
        cout<<"构造函数"<<endl;
        this->m_A = age;
    }
    
    void showData()
    {
        cout<<this->m_A<<endl;
    }
    ~Person()
    {
        cout<<"Person的析构函数"<<endl;
    }
private:
    int m_A;
};

class SmartPoint
{
public:
    SmartPoint(Person* person)
    {
        m_person = person;
    }
    
    Person* operator->()
    {
        return m_person;
    }
    Person& operator*()
    {
        return *m_person;
    }
    
    ~SmartPoint()
    {
        if(this->m_person)
        {
            delete m_person;
            m_person = NULL;
        }
    }
private:
    Person* m_person;
};

// void test_01()
// {
    // Person* p = new Person(18);
    // p->showData();
    // //指针对象不delete的话  不会调用析构函数
// }

void test_01()
{
    SmartPoint s(new Person(18)); //定义了一个智能指针类  但是现在体现出它是指针  
    //所以需要重定义指针->
    s->showData();
    (*s).showData();
}

=赋值运算符的重载

系统提供四个函数:默认构造函数 拷贝函数 析构函数 赋值函数(operator =)

当类成员有在堆中申请空间的变量成员 就会发生浅拷贝错误

所以 需要重载赋值函数实现深拷贝

需要返回本类引用 适用连续多次赋值操作

class Person
{
public:
    Person(char* name, int age)
    {
        this->m_Name = new char[strlen(name)+1];
        strcpy(this->m_Name, name);
        this->m_Age = age;
    }
    
    Person(Person& p)
    {
        this->m_Name = new char[strlen(p.m_Name)+1];
        strcpy(this->m_Name, p.m_Name);
        this->m_Age = p.m_Age;
    }
    
    
    Person& operator= (const Person &p)
    {
        if (this->m_Name != NULL)
        {
            delete[]this->m_Name;
            m_Name = NULL;
        }
        this->m_Name = new char[strlen(p.m_Name) + 1];
        strcpy(this->m_Name, p.m_Name);
        this->m_Age = p.m_Age;
        return *this;
    }
    char* m_Name;
    int m_Age;
    ~Person()
    {
        if (this->m_Name!=NULL)
        { 
            delete []this->m_Name;
            this->m_Name = NULL;
        }
    }
};


void test_01()
{
    Person p1("Tom", 10);
    Person p2("Lis", 20);
    p2 = p1;             //错误需要重载赋值运算符
    cout << "p2姓名:" << p2.m_Name << " p2 年龄:" << p2.m_Age << endl;
    Person p3 = p2;
    cout << "p3姓名:" << p3.m_Name << " p3 年龄:" << p3.m_Age << endl;
}

[]数组运算符重拷贝

需要返回int引用 如果返回int值的话 不可为数组赋值(值不可在赋值号左边) 只可打印

class MyArray
{
public:
    //无参构造函数  用户没有指定容量 初始化为10
    MyArray();
    //有参构造函数  用户指定容量初始化
    explicit MyArray(int capacity);
    
    
    //用户操作接口
    //根据位置添加元素
    void SetData(int pos,int val);
    //获得指定位置数据
    int GatDate(int pos);
    //尾插法
    void PushBack(int val);
    //获得长度
    int GetLenth();
    //析构函数  释放内存空间
    ~MyArray();
    int& operator [](int size)
    {
        return *(this->pAdress+size);
        
    }
private:
    int mCapacity;    //数组一共可以容纳多少容量
    int mSize;        //当前元素的大小
    int* pAdress;    //指向存储数据的空间
};

//无参构造函数  用户没有指定容量 初始化为10
MyArray::MyArray()
{
    mCapacity = 10;
    mSize = 0;
    pAdress = new int[mCapacity];
}
//有参构造函数  用户指定容量初始化
MyArray::MyArray(int capacity)
{
    mCapacity = capacity;
    mSize = 0;
    pAdress = new int[mCapacity];
}

//用户操作接口
//根据位置添加元素
void MyArray::SetData(int pos,int val)
{
    pAdress[pos] = val;
}
//获得指定位置数据
int MyArray::GatDate(int pos)
{
    return pAdress[pos];
}
//尾插法
void MyArray::PushBack(int val)
{
    pAdress[mSize] = val;
    mSize++;
}
//获得长度
int MyArray::GetLenth()
{
    return mSize;
}
//析构函数  释放内存空间
MyArray::~MyArray()
{
    delete []pAdress;
}

void test_01()
{
    MyArray arr;
    for(int i=0;i<10;i++)
    {
        arr.PushBack(100+i);
    }
    for(int i=0;i<arr.GetLenth();i++)
    {
        cout<<arr.GatDate(i)<<endl;
    }
    cout<<"---------------"<<endl;
    arr[0] = 1000;
    cout<<arr[0]<<endl;
}

int main(int argc, char* argv[])
{
    test_01();

    return 0;
}

仿函数重载

重载函数调用运算符:为STL算法提供策略。(可完成链式编程的操作)

class Data{
public:
    Data& operator()(char * p)  //仿函数重载
    {
        cout<<p;
        return *this;  //当前对象调的函数,返回*this
    }
};
void test01()
{
    Data d;   //d.operator()("hello")
    d("hello")("world")("666");
}

项目:利用类和重载的知识点 写一个自己的string类

内容: 拷贝构造函数的深拷贝 赋值构造函数的深拷贝 析构函数的释放堆内存

重载>> << + == != [] 的知识

#include <iostream>
#include <cstring>

using namespace std;

class Mystring
{
public:
    friend ostream& operator<< (ostream& cout,const Mystring& s);
    friend istream& operator>> (istream& cin,Mystring& s);
    Mystring(){}
    Mystring(const char* str)
    {
        m_Str = new char[strlen(str)+1];
        strcpy(m_Str,str);
        Str_len = strlen(str)+1;
    }
    Mystring(const Mystring& s)
    {
        m_Str = new char[s.Str_len];
        strcpy(m_Str,s.m_Str);
        Str_len = s.Str_len;
    }
    ~Mystring()
    {
        if(m_Str != NULL)
        {
            delete []m_Str;
            m_Str = NULL;
        }
    }
        Mystring& operator= (const Mystring& s);
        Mystring& operator= (const char* str);
        Mystring operator+ (const Mystring& str);
        Mystring operator+ (const char* str);
        char& operator[] (int num);
        bool operator== (const Mystring& str);
        bool operator!= (const Mystring& str);
   private:
    char* m_Str;
    int Str_len;
};

char& Mystring::operator[] (int num)
{
        return *(m_Str+(num));
}

ostream& operator<< (ostream& cout,const Mystring& s)
{
    cout<<"\""<<s.m_Str<<"\""<<"长度为"<<s.Str_len;
        return cout;
}
istream& operator>> (istream& cin,Mystring& s)
{
    if(s.m_Str!=NULL)
    {
        delete []s.m_Str;
        s.m_Str = NULL;
    }
    char temp[1024];
            cin>>temp;
        s.m_Str = new char[strlen(temp)+1];
        strcpy(s.m_Str,temp);
        s.Str_len = strlen(temp)+1;
            return cin;
}


Mystring Mystring::operator+ (const char* str)
{
        int newsize = strlen(str)+this->Str_len;
        char* temp = new char[newsize];
        strcat(temp,this->m_Str);
        strcat(temp,str);
        Mystring s = temp;
        delete []temp;
        return s;
}

Mystring Mystring::operator+ (const Mystring& str)
{
        int newsize = str.Str_len + this->Str_len-1;
        char* temp = new char[newsize];
        strcat(temp,this->m_Str);
        strcat(temp,str.m_Str);
        Mystring s = temp;
        delete []temp;
        return s;
}

Mystring& Mystring::operator= (const Mystring& s)
{
        if(this->m_Str != NULL)
        {
        delete []this->m_Str;
        this->m_Str = NULL;
        }
        this->m_Str = new char[s.Str_len];
        strcpy(this->m_Str,s.m_Str);
        this->Str_len = s.Str_len;
        return *this;
}

Mystring&  Mystring::operator= (const char* str)
{
        if(this->m_Str != NULL)
        {
            delete []this->m_Str;
        this->m_Str = NULL;
        }
        this->m_Str = new char[strlen(str)+1];
        strcpy(this->m_Str,str);
        this->Str_len = strlen(str)+1;
        return *this;
}
bool Mystring::operator!= (const Mystring& str)
{
        int i=0;
    while(this->m_Str[i]!='\0'&&str.m_Str[i]!='\0')
    {
        if(this->m_Str[i]!=str.m_Str[i])
        {
            break;
        }
        i++;
    }
    if(this->m_Str[i]==str.m_Str[i])
    {
        return false;
    }
    else
    {
        return true;
    }
}

bool Mystring::operator== (const Mystring& str)
{
    int i=0;
    while(this->m_Str[i]!='\0'&&str.m_Str[i]!='\0')
    {
        if(this->m_Str[i]!=str.m_Str[i])
        {
            break;
        }
        i++;
    }
    if(this->m_Str[i]==str.m_Str[i])
    {
        return true;
    }
    else
    {
        return false;
    }
}

void test_01()
{
    Mystring str1("hello");
    cout<<str1<<endl;
    str1 = "abc";
    cout<<str1<<endl;
    Mystring str2 = str1;
    cout<<str2<<endl;
    Mystring str3 = str1 + str2;
    cout<<str3<<endl;
    if(str1==str2)
    {
        cout<<"=="<<endl;
    }
    else
    {
        cout<<"!="<<endl;
    }
    if(str1!=str2)
    {
        cout<<"!="<<endl;
    }
    else
    {
        cout<<"=="<<endl;
    }
    cin>>str1;
    cout<<str1<<endl;
    cout<<str1[0]<<endl;
    str1[0] = 'w';
    cout<<str1<<endl;
}

int main(int argc, char* argv[])
{
    
    test_01();
    
    return 0;
}

今天代码量有点多 但是坚持就是胜利 自己可以把这些重载运算符完成 就离天下无敌不远了(ง •_•)ง

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值