day5,打卡的一天,还有什么深度学习的创新点,真的难找

应该说昨天晚上看了运算符重载,发现这块上了好强的难度,需要好好消化一下了

运算符重载

概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

加号运算符重载  

实现两个自定义数据类型相加的运算,如何实现用+号也能让两个类中的属性相加

void test01() 
{
	Person p1;
	p1.m_a = 10;
	p1.m_b = 10;

	Person p2;
	p2.m_a = 10;
	p2.m_b = 10;

	Person p3 = p1 + p2;//如何实现
class Person
{
public:
	int m_a;
	int m_b;

public:
//通过成员函数重载
	Person PersonaddPerson(Person& p)
	{
		Person temp;
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
	}

};

通过成员函数重载这个+,实现我们想要做的加法,但是每个人的编程习惯不同,这样会导致很多函数名,因此编辑器自己起了一个名字,称为operator,上述代码就变为

Person operator+ (Person& p) 
{
	Person temp;
	temp.m_a = this->m_a + p.m_a;
	temp.m_b = this->m_b + p.m_b;
	return temp;
}

接下来就调用这个成员函数

p3 = p1.operator+(p2)//本质是这个,可以简化为Person p3 = p1 + p2

上述便是通过成员函数重载+号的方法,下面是用全局函数重载+号

Person& operator+ (Person &p1 , Person &p2)
{
    Person temp ;
    temp.m_a = p1.m_a + p2.m_a;
    temp.m_b = p1.m_b + p2.m_b;
    return temp;
}

上述代码调用的本质是

Person p3 = operator+(p1,p2);//也可以简写成Person p3 = p1 + p2

如果我想实现Person p4 = p1 + 100这个功能呢,一样也可以通过全局函数重载实现这个功能

Person& operator+ (Person &p1 , int num)
{
    Person temp ;
    temp.m_a = p1.m_a + num;
    temp.m_b = p1.m_b + num;
    return temp;
}

如果一开始将int m_a; int m_b;设置成private,可以使用之前学的友元 即全局函数做友元,或者成员函数做友元均可实现

总结:1:对于内置的数据类型的表达式的运算符时不可能改变的   2:不要滥用运算符重载

左移运算符重载

可以输出自定义数据类型

class Person 
{
	
public:
	Person(int a , int b ) 
	{
		m_a = a;
		m_b = b;
	}
private:
	int m_a;
	int m_b;

};

写到这里的时候如果想是用成员函数重载左移运算符会发现

void operator<<( ) 
{

}
//按照之前的原理,调用这个成员函数的本质应该是
// p.operator<<()  简化版本p << cout

会发现无法实现cout在左侧,所以不会利用成员函数重载<<运算符 。

这时只能使用全局函数重载左移运算符

ostream &operator<<( ostream &cout , Person &p)
{
    cout << "m_a = " << p.m_a << "m_b" << p.m_b;
    return cout ;  // cout 重载的重点 , 为了支持链式调用和保持与标准库的一致性
}

这里可能想不到return cout。如果这里没有return cout 会发现 cout << p << endl; 在第二个<<的时候会报错,要使用链式编程思想,上述函数返回的是void,所以不能进行函数追加。

之后会发现m_a,m_b的属性是私有的,所以我们要让全局函数做友元添加到person类中,便实现了重载左移运算符。

friend ostream &operator<<( ostream &cout , Person &p);

总结:重载左移运算符配合友元可以实现输出自定义类型的数据

递增运算符重载

这玩意是真的难呀,感觉很多点想不到

class MyInteger 
{
    friend ostream& operator<< (ostream& cout , MyInteger & myint);  
public:
	MyInteger() 
	{
		m_Num = 0;
	}

private:
	int m_Num;

};

使用成员函数重载前置递增运算符

MyInteger& operator++()
{
    m_Num ++ ; 
    return *this;//		return *this;//返回引用是为了一直对一个数据进行递增
}


//测试代码
void test01() 
{
	MyInteger myint;
	cout << ++myint << endl;  //cout << ++myint << endl;

}

这边需要使用上述的<<左移运算符的重载,我们再来写一遍

ostream& operator<< (ostream& cout , MyInteger & myint)    
{
    cout << myint.m_Num;
    return cout;
}

上述便是使用成员函数重载前置递增运算符

接下来使用成员函数实现后置递增运算符

和前置递增一样的思想,但是在传入参数的时候 有个int,这是函数重载的区分条件。int代表占位参数,可以用于区分前置和后置递增。

//后置递增 a++ 先打印  后递增
void operator++(int)
{
    MyInterger temp = *this ;
    m_Num++;
    return temp; // 后置递增会先打印然后再递增,所以这边需要有一个临时变量来接收
}

最后一行代码的时候如果返回引用的话,这边是返回局部变量的引用,局部变量在执行完之后会被释放

但是在后置递增这边,直接运行是不行的,比如下面的test

void test02() 
{
	MyInteger myint;
	cout << myint++ << endl;
	cout << myint << endl;

}

在myint++后面的<<左移运算符会报错,显示没有可以用的运算符,网上deepseek查了才知道,要将左移运算符重载的代码稍微改一下才可以,需要将 operator<< 的参数改为 const MyInteger& ,以支持常对象的输出。(反正我是不懂的哦,要记住这玩意),使用这个const修饰的引用在前置递增和后置递增都不会报错。

ostream& operator<< (ostream& cout, const MyInteger& myint)
{
	cout << myint.m_Num;
	return cout;
}

赋值运算符重载

C++编译器至少给一个类添加4个函数  

无参构造函数 无参析构函数 拷贝构造函数 赋值运算符operator = 

如果类中有属性指向堆区,做赋值操作的时候会出现深浅拷贝问题 这是话就需要自建深拷贝构造函数

我们先来确定赋值运算符是需要做什么的

void test01() 
{
	Person p1(18);
	Person p2(20);

	p2 = p1; // 赋值运算操作   类似 a = 1 , b = 2 , b = a 的操作

}
class Person
{
public:

    Person(int age )
    {    
        m_age = new int(age);
    }
    ~Person()
    {
        if(m_age != NULL)//先判断是否为空,如果不为空先进行清空
        {
            delete m_age;
            m_age = NULL;
        } 
    }    

    Person& operator=(Person &p)
    {
        if(m_age != NULL)//先判断是否为空,如果不为空先进行清空
        {
            delete m_age;
            m_age = NULL;
        }
        m_age = new int(*p.m_age);//在堆区开辟一块新内存接收数据
        return *this;//返回对象本身
    }

    int *m_age;
};

赋值运算操作这里有一个坑就在析构的时候浅拷贝的问题  堆区内存重复释放

关系重载运算符

重载关系运算符,可以让两个自定义类型的对象进行对比操作 (主要符号是 == 和 !=)

void test01() 
{
	Person p1("Tom", 18);
	Person p2("Jerry", 18);

	if (p1 == p2) 
	{
		cout << "p1和p2 是相等的" << endl;

	}
	else 
	{
		cout << "p1和p2 是不相等的" << endl;
	}
}

先来看一下上面的测试代码,这样我们才能明白关系重载运算符需要做什么。上述代码中想实现使用 == 关系运算符 比较p1 和 p2 这两个的关系,知道了需求我们来写成员函数重载

class Person
{
public:
    
    Person(string name , int age )
    {    
        m_name = name ;
        m_age = age ;        
    }
    
    bool operator==(Person &p)
    {
        if (*this->m_name == p.m_name && *this->m_age == p.m_age)
        {
            return true;
        }
        return false;
    }

  
    string m_name ;
    int m_age;

};

重载=!和上述一样的,就不再继续写相似的了

函数调用运算符重载

函数调用运算符()也可以重载
由于重载后使用的方式非常像函数调用,因此称为仿函数
仿函数没有固定的写法,非常灵活   STL

函数调用运算符重载有什么用呢?接下来看测试代码

void test01() 
{
	Myprint myprint;
	myprint("hello world");//由于使用起来类似函数调用,因此称为仿函数

}
class Myprint // 打印
{
public:
    void operator()(string text)
    {
        cout << text << endl;
    }
};

这样就可可以正确调用打印输出了,由于使用起来类似函数调用,因此称为仿函数

上述代码实现了打印输出类,下面再实现一个加法类

void test02() 
{
	Myadd add; 
	int ret = add(1, 2);
	cout << "ret = " << ret << endl;

}
class Myadd
{
public:
    int operator()(int a , int b )
    {
        return a + b ;
    }
};
//匿名函数对象   Myadd()通过一个类名加()创建一个匿名对象
cout << Myadd()(100, 100) << endl;

上述就结束啦,前面三个的难度还是比较大的,到了后面三个重载就简单多了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值