[C++核心编程-08]----C++类和对象之运算符重载

🎩 欢迎来到技术探索的奇幻世界👨‍💻

📜 个人主页@一伦明悦-CSDN博客

✍🏻 作者简介: C++软件开发、Python机器学习爱好者

🗣️ 互动与支持:💬评论      👍🏻点赞      📂收藏     👀关注+

如果文章有所帮助,欢迎留下您宝贵的评论,点赞加收藏支持我,点击关注,一起进步!

 前言       

        在C++中,运算符重载是一种允许你重新定义标准操作符(如+、-、*、/等)的特性,以便它们适用于自定义的数据类型。这种功能使得你可以像操作内置类型一样自然地操作自定义类型的对象。运算符重载是面向对象编程的一个重要特性,它增强了代码的可读性和可维护性。

正文       

01-运算符简介        

        运算符重载允许你对类的对象使用C++内置的运算符进行操作。例如,你可以重载+运算符来实现两个对象的相加,或者重载*运算符来实现对象的乘法操作。这样一来,你就可以像处理基本数据类型一样处理自定义的数据类型。

        在C++中,你可以通过重载类的成员函数或全局函数来实现运算符重载。如果你选择在类中重载运算符,那么运算符函数将作为类的成员函数来定义。如果你选择在类外部重载运算符,那么你需要使用全局函数的形式来定义运算符函数。

        在C++中,你可以通过重载成员函数或全局函数来实现运算符重载。以下是一个简单的示例,说明如何重载+运算符来实现两个复数对象的相加:

        在上示例中,我们创建了一个名为Complex的类来表示复数。我们重载了+运算符,使其能够将两个Complex对象相加。然后,在主函数中,我们创建了两个Complex对象并使用重载的+运算符将它们相加,最后打印了结果。

#include <iostream>

class Complex {
private:
    double real;
    double imaginary;

public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imaginary(i) {}

    // 重载+运算符
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imaginary + other.imaginary);
    }

    // 打印复数
    void print() const {
        std::cout << "(" << real << " + " << imaginary << "i)" << std::endl;
    }
};

int main() {
    Complex c1(2.0, 3.0);
    Complex c2(1.0, 2.0);
    
    Complex result = c1 + c2; // 使用重载的+运算符

    std::cout << "Result of addition: ";
    result.print();

    return 0;
}

02-加号运算符重载        

        当重载加号运算符(+)时,可以定义在两个对象之间的相加操作。这样,可以使用加号运算符直接对两个对象进行相加,而不必调用一个特定的成员函数来执行这个操作。这种操作增加了代码的可读性和简洁性。

        在C++中,可以通过在类中或类外部定义特定的成员函数或全局函数来重载加号运算符。下面分别介绍在类中和类外部重载加号运算符的方法。

        在类中重载加号运算符: 在这里,operator+是加号运算符的重载函数,returnType是运算符函数的返回类型,const ClassName& other是另一个对象的引用,表示要与当前对象相加的对象。

class ClassName {
public:
    returnType operator+(const ClassName& other) {
        // 重载的加号运算符实现
    }
};

        下面给出具体例子,在这个例子中,我们在Complex类中重载了加号运算符。在重载函数中,我们定义了两个Complex对象相加的操作,并返回相加后的结果。

#include <iostream>

class Complex {
private:
    double real;
    double imaginary;

public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imaginary(i) {}

    // 重载+运算符
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imaginary + other.imaginary);
    }

    // 打印复数
    void print() const {
        std::cout << "(" << real << " + " << imaginary << "i)" << std::endl;
    }
};

int main() {
    Complex c1(2.0, 3.0);
    Complex c2(1.0, 2.0);
    
    Complex result = c1 + c2; // 使用重载的+运算符

    std::cout << "Result of addition: ";
    result.print();

    return 0;
}

        在类外部重载加号运算符:在这里,operator+是加号运算符的重载函数,returnType是运算符函数的返回类型,const ClassName& obj1const ClassName& obj2是要相加的两个对象的引用。

returnType operator+(const ClassName& obj1, const ClassName& obj2) {
    // 重载的加号运算符实现
}

         类外部重载加号运算符的例子:在这个例子中,我们在Complex类外部重载了加号运算符。在重载函数中,我们定义了两个Complex对象相加的操作,并返回相加后的结果。

#include <iostream>

class Complex {
private:
    double real;
    double imaginary;

public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imaginary(i) {}

    // 打印复数
    void print() const {
        std::cout << "(" << real << " + " << imaginary << "i)" << std::endl;
    }
};

// 在类外部重载+运算符
Complex operator+(const Complex& c1, const Complex& c2) {
    return Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}

int main() {
    Complex c1(2.0, 3.0);
    Complex c2(1.0, 2.0);
    
    Complex result = c1 + c2; // 使用重载的+运算符

    std::cout << "Result of addition: ";
    result.print();

    return 0;
}

        下面给出具体代码分析应用过程,代码演示了如何在C++中进行运算符重载,特别是加号运算符(+)。逐步解释:

         首先,定义了一个名为 Person 的类,其中有两个公有成员变量 m_A 和 m_B,代表人的某些属性。

        接着,通过两种不同的方式重载了加号运算符:

        通过成员函数重载:注释掉的部分代码是使用成员函数重载加号运算符的示例。这种方式是在类内定义一个成员函数,该函数接受一个对象作为参数,并执行加法操作。

        通过全局函数重载:实际使用的方式是在类外定义一个全局函数,该函数接受两个对象作为参数,并执行加法操作。

        另外,还重载了一个全局函数,使得 Person 类型对象可以与整数进行相加操作。

  test01() 函数用于测试加号运算符重载的效果。在函数内部,创建了两个 Person 类型对象 p1 和 p2,并设置它们的属性值。        

        然后,分别演示了两种方式重载加号运算符的调用方式:

        使用成员函数重载加号运算符时,可以像调用普通成员函数一样使用 . 运算符进行调用,即 p1.operator+(p2)

        使用全局函数重载加号运算符时,直接使用加号进行调用,即 p1 + p2

        最后,演示了使用全局函数重载加号运算符将 Person 对象与整数相加的情况,即 p1 + 100

#include <iostream>
using namespace std;

// 加号运算符重载
class Person
{
public: 

	// 1、实现成员函数重载+号    成员函数就是在类里定义的函数,可以少传入一个参数

// 	Person operator+(Person &p)  // operator+这个就是编译器自带的一个函数名称,使用此名称,后面才能简化,其他代码自己写
// 	{
// 		Person temp;
// 		temp.m_A = this->m_A + p.m_A;
// 		temp.m_B = this->m_B + p.m_B;
// 		return temp;
// 
// 	}

	int m_A;
	int m_B;
};

// 2、实现全局函数重载+号    全局函数就是在类外定义的函数,需要同时传入所有的所需参数
Person operator+(Person &p1, Person &p2)
{
	Person temp;
	// 因为m_A是公有的成员变量,因此可以调用
	temp.m_A = p1.m_A + p2.m_A;
	temp.m_B = p1.m_B + p2.m_B;
	return temp;
}
Person operator+(Person &p1, int num)   // 这里采用引用方式,可以防止值传递的时候再进行拷贝一份数据,用不用都可以
{
	Person temp;
	// 因为m_A是公有的成员变量,因此可以调用
	temp.m_A = p1.m_A + num;
	temp.m_B = p1.m_B + num;
	return temp;
}

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.operator+(p2);
	//全局函数重载本质调用
//	Person p3 = operator+(p1,p2);

	Person p3 = p1 + p2;   // 这句代码其实是由 Person p3 = p1.operator+(p2);简化而来

	// 运算符重载,也可以发生函数重载,比如如果需要Person类型加上一个整型数据
	// 相当于 Person p4 = operator+(p1, num);
	Person p4 = p1 + 100;


	cout << "p3.m_A = " << p3.m_A << endl;
	cout << "p3.m_B = " << p3.m_B << endl;

	cout << "p4.m_A = " << p4.m_A << endl;
	cout << "p4.m_B = " << p4.m_B << endl;
}

int main()
{
	test01();

	system("pause");
	return 0;
}

        示例运行结果如下图所示:

03-左移运算符重载        

        当重载左移运算符(<<)时,可以定义在自定义类对象上执行左移操作的行为。这使得可以像使用标准输出流对象一样使用左移运算符来输出自定义对象的信息。这种操作可以增强代码的可读性和简洁性。

        在C++中,可以通过在类内部或类外部定义特定的成员函数或全局函数来重载左移运算符。以下是分别在类内部和类外部重载左移运算符的方法。

        在类内部重载左移运算符:operator<< 是左移运算符的重载函数,std::ostream& os 是输出流对象的引用,const ClassName& obj 是要输出的对象的引用。

class ClassName {
public:
    friend std::ostream& operator<<(std::ostream& os, const ClassName& obj) {
        // 重载的左移运算符实现
        os << obj.member1 << " " << obj.member2; // 假设输出对象的成员变量为 member1 和 member2
        return os;
    }
};

        实现在类中重载左移运算符的例子:在这个例子中,我们在 Person 类中重载了左移运算符。在重载函数中,我们定义了如何输出 Person 对象的信息,并使用 std::ostream 对象来进行输出。

#include <iostream>

class Person {
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << "Name: " << person.name << ", Age: " << person.age;
        return os;
    }

private:
    std::string name;
    int age;

public:
    Person(const std::string& n, int a) : name(n), age(a) {}
};

int main() {
    Person p("John", 30);
    std::cout << p << std::endl; // 使用重载的<<运算符输出对象信息

    return 0;
}

        在类外部重载左移运算符:operator<< 是左移运算符的重载函数,std::ostream& os 是输出流对象的引用,const ClassName& obj 是要输出的对象的引用。

std::ostream& operator<<(std::ostream& os, const ClassName& obj) {
    // 重载的左移运算符实现
    os << obj.member1 << " " << obj.member2; // 假设输出对象的成员变量为 member1 和 member2
    return os;
}

        实现在类外部重载左移运算符的例子:在这个例子中,我们在类外部重载了左移运算符。在重载函数中,我们定义了如何输出 Person 对象的信息,并使用 std::ostream 对象来进行输出。

#include <iostream>

class Person {
    friend std::ostream& operator<<(std::ostream& os, const Person& person);

private:
    std::string name;
    int age;

public:
    Person(const std::string& n, int a) : name(n), age(a) {}
};

std::ostream& operator<<(std::ostream& os, const Person& person) {
    os << "Name: " << person.name << ", Age: " << person.age;
    return os;
}

int main() {
    Person p("John", 30);
    std::cout << p << std::endl; // 使用重载的<<运算符输出对象信息

    return 0;
}

        下面给出具体代码分析应用过程,这段代码演示了如何在C++中进行左移运算符(<<)的重载,以便能够像使用标准输出流对象一样输出自定义类的对象信息。逐步解释:

        首先,定义了一个名为 Person 的类,其中有两个公有成员变量 m_A 和 m_B,代表人的某些属性。

        接着,通过两种不同的方式尝试重载左移运算符:

        通过成员函数重载(注释掉的部分):在成员函数中尝试重载左移运算符,但在C++中,左移运算符 << 的重载必须是全局函数或类的友元函数,不能以成员函数的形式重载。

        通过全局函数重载左移运算符:在类外定义了一个全局函数,该函数接受一个输出流对象 ostream 和一个 Person 对象的引用,并输出该对象的信息。

  test01() 函数用于测试重载的左移运算符的效果。在函数内部,创建了一个 Person 类型对象 p,并设置了其属性值。

        在 main() 函数中,调用了 test01() 函数,并输出了 p 对象的信息。

#include <iostream>
using namespace std;

// 左移运算符重载   和加号一样,两种重载方式

class Person
{
public:
	// 1、成员函数重载
// 	void operator << (ostream &cout , Person &p)
// 	{
// 		cout << "m_A = " << p.m_A << " m_B = " << p.m_B;
// 	}

	int m_A;
	int m_B;
};

// 2、只能利用全局函数重载左移运算符
ostream & operator << (ostream &cout, Person &p)
{
	cout << "m_A = " << p.m_A << " m_B = " << p.m_B;
	return cout;
}

void test01()
{
	Person p;
	p.m_A = 10;
	p.m_B = 10;
	cout << p << endl;

}

int main()
{
	test01();
	system("pause");
	return 0;
}

         示例运行结果如下图所示:

04-递增运算符重载       

        当重载递增运算符(++)时,可以定义在自定义类对象上执行递增操作的行为。递增运算符通常有两种形式:前置递增和后置递增。前置递增返回递增后的对象的引用,而后置递增返回递增前的对象的副本。这使得可以像使用内置数据类型一样使用递增运算符来操作自定义对象。

        在C++中,可以通过在类内部或类外部定义特定的成员函数或全局函数来重载递增运算符。以下是分别在类内部和类外部重载前置递增运算符和后置递增运算符的方法。

        在类内部重载递增运算符:在这里,operator++ 是递增运算符的重载函数。对于前置递增,它返回一个引用,因为递增后的对象可能会在表达式中继续使用。对于后置递增,它返回递增前的对象的副本,因为它需要返回原始值而不是递增后的值。

class ClassName {
public:
    ClassName& operator++() {
        // 实现前置递增操作
        // 修改对象的状态
        return *this; // 返回递增后的对象的引用
    }

    ClassName operator++(int) {
        // 实现后置递增操作
        // 先保存递增前的对象副本
        // 修改对象的状态
        return copy; // 返回递增前的对象的副本
    }
};

        实现在类中重载前置递增运算符和后置递增运算符的例子:在这个例子中,定义了一个 Counter 类,其中包含一个 count 成员变量。在类中重载了前置递增运算符和后置递增运算符,通过增加 count 的值来模拟递增操作。

#include <iostream>

class Counter {
private:
    int count;

public:
    Counter(int c) : count(c) {}

    Counter& operator++() {
        ++count;
        return *this;
    }

    Counter operator++(int) {
        Counter temp = *this;
        ++(*this);
        return temp;
    }

    int getCount() const {
        return count;
    }
};

int main() {
    Counter c(5);
    std::cout << "Before increment: " << c.getCount() << std::endl;

    ++c; // 前置递增
    std::cout << "After pre-increment: " << c.getCount() << std::endl;

    c++; // 后置递增
    std::cout << "After post-increment: " << c.getCount() << std::endl;

    return 0;
}

        在类外部重载递增运算符:在这里,operator++ 是递增运算符的重载函数。对于前置递增,它返回一个引用,因为递增后的对象可能会在表达式中继续使用。对于后置递增,它返回递增前的对象的副本,因为它需要返回原始值而不是递增后的值。

ClassName& operator++(ClassName& obj) {
    // 实现前置递增操作
    // 修改对象的状态
    return obj; // 返回递增后的对象的引用
}

ClassName operator++(ClassName& obj, int) {
    // 实现后置递增操作
    // 先保存递增前的对象副本
    // 修改对象的状态
    return copy; // 返回递增前的对象的副本
}

        实现在类外部重载前置递增运算符和后置递增运算符的例子:在这个例子中,我们在类外部重载了前置递增运算符和后置递增运算符,并将其声明为友元函数,以便能够访问类的私有成员 count。在重载函数中,我们实现了相应的递增操作,并返回递增后或递增前的对象。

#include <iostream>

class Counter {
private:
    int count;

public:
    Counter(int c) : count(c) {}

    friend Counter& operator++(Counter& obj) {
        ++obj.count;
        return obj;
    }

    friend Counter operator++(Counter& obj, int) {
        Counter temp = obj;
        ++obj;
        return temp;
    }

    int getCount() const {
        return count;
    }
};

int main() {
    Counter c(5);
    std::cout << "Before increment: " << c.getCount() << std::endl;

    ++c; // 前置递增
    std::cout << "After pre-increment: " << c.getCount() << std::endl;

    c++; // 后置递增
    std::cout << "After post-increment: " << c.getCount() << std::endl;

    return 0;
}

        下面给出具体代码分析应用过程,这段代码演示了如何重载递增运算符(++)以及左移运算符(<<),并展示了前置递增、后置递增和输出对象的操作。代码解释:

        首先,定义了一个名为 MyInteger 的类,其中有一个私有成员变量 m_Num,表示自定义的整数类型的值。

        在类内部分别重载了前置递增运算符和后置递增运算符:

   operator++():用于实现前置递增,返回类型为 MyInteger&,即引用类型,以支持链式操作。在该函数内部,将 m_Num 递增,并返回递增后的对象的引用。

   operator++(int):用于实现后置递增,其中 int 是一个占位参数,标识这是后置递增的重载版本。在该函数内部,先记录当前对象的值到临时变量 temp,然后将 m_Num 递增,并返回记录的临时变量。

        在类外部重载了左移运算符 operator<<,用于输出 MyInteger 对象的值。

  test01() 函数演示了前置递增的使用方式,通过连续两次前置递增对对象进行操作,并输出结果。

  test02() 函数演示了后置递增的使用方式,通过后置递增对对象进行操作,并输出结果。

        在 main() 函数中调用了 test02() 函数,测试了后置递增的效果,并输出了相应的结果。

#include <iostream>
using namespace std;

// 重载递增运算符

// 自定义整型
class MyTnteger
{

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

	// 重载前置++运算符  使用引用返回主要是基于链式编程思想,每一次返回的都是同一个对象,
	// 因此可以持续对通体个对象进行操作
	// 比如 如果使用的是值传递的方式,会正常运行,但是test01()函数里不会输出两个2,而是一个2,一个1
	MyTnteger & operator++()
	{
		// 先进行++运算  使其内部属性进行递增操作
		m_Num++;     //这里怎么写都无所谓,无论++在前还是在后,都是进行加1操作
		// 然后再将自身返回
		return *this;
	}
	// 重载后置++运算符

	MyTnteger  operator++(int)   // int 是一个占位参数,可以实现函数重载
	{
		MyTnteger temp = *this;   // 先记录当前值,再进行++
		m_Num++;   //这里怎么写都无所谓,无论++在前还是在后,都是进行加1操作
		return temp;

	}

private:
	int m_Num;
};


//重载左移运算符
ostream & operator<<(ostream &cout, MyTnteger myint)
{
	cout << myint.m_Num;
	return cout;
}

void test01()
{

	MyTnteger myint;    // 这是自己自定义的一个整型数据
	cout << ++(++myint) << endl;
	cout <<myint << endl;
}

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

}

int main()
{

	test02();

	system("pause");
	return 0;
}

        示例运行结果如下图所示: 

05-赋值运算符重载       

        赋值运算符(=)重载允许自定义类对象的赋值行为。当重载赋值运算符时,可以定义对象之间的赋值操作的行为,以便在类中使用赋值语句像内置类型一样对对象进行赋值。

        在C++中,可以通过在类内部或类外部定义特定的成员函数或全局函数来重载赋值运算符。以下是分别在类内部和类外部重载赋值运算符的方法。

        在类内部重载赋值运算符:在这里,operator= 是赋值运算符的重载函数。它接受一个常量引用作为参数,即右操作数,然后检查是否进行了自我赋值。如果不是自我赋值,则执行赋值操作。

class ClassName {
public:
    ClassName& operator=(const ClassName& rhs) {
        // 检查自赋值
        if (this != &rhs) {
            // 执行赋值操作
            // 将rhs的值赋给当前对象
        }
        return *this;
    }
};

        实现在类中重载赋值运算符的例子:在这个例子中,MyString 类重载了赋值运算符,以支持对象之间的赋值操作。在赋值运算符的实现中,首先检查是否进行了自我赋值,然后释放原有内存,分配新的内存,并复制字符串内容。

class MyString {
private:
    char* buffer;

public:
    // 构造函数、析构函数和其他成员函数的实现省略

    // 重载赋值运算符
    MyString& operator=(const MyString& rhs) {
        if (this != &rhs) {
            delete[] buffer; // 释放原有内存
            buffer = new char[strlen(rhs.buffer) + 1]; // 分配新内存
            strcpy(buffer, rhs.buffer); // 复制字符串
        }
        return *this;
    }
};

        在类外部重载赋值运算符:在这里,operator= 是赋值运算符的重载函数。它接受两个参数,分别是左操作数(要赋值的对象)和右操作数(赋值的对象的值)。然后检查是否进行了自我赋值,如果不是自我赋值,则执行赋值操作。

ClassName& operator=(ClassName& lhs, const ClassName& rhs) {
    // 检查自赋值
    if (&lhs != &rhs) {
        // 执行赋值操作
        // 将rhs的值赋给lhs对象
    }
    return lhs;
}

       实现在类外部重载赋值运算符的例子:在这个例子中,我们在类外部重载了赋值运算符,以支持对象之间的赋值操作。在重载函数中,首先检查是否进行了自我赋值,然后释放原有内存,分配新的内存,并复制字符串内容。

MyString& operator=(MyString& lhs, const MyString& rhs) {
    if (&lhs != &rhs) {
        delete[] lhs.buffer; // 释放原有内存
        lhs.buffer = new char[strlen(rhs.buffer) + 1]; // 分配新内存
        strcpy(lhs.buffer, rhs.buffer); // 复制字符串
    }
    return lhs;
}

        下面给出具体代码分析应用过程,这段代码演示了如何在类中重载赋值运算符(=),并实现了深拷贝,以避免浅拷贝带来的问题。代码解释如下:

        定义了一个名为 Person 的类,其中包含一个 int 类型的指针成员 m_Age,用于表示人的年龄。

        类中提供了一个有参构造函数,用于初始化 m_Age 成员。

        定义了析构函数,用于释放动态分配的内存。

        在类中重载了赋值运算符 operator=。在赋值运算符的重载函数中,首先进行了深拷贝,即通过动态分配内存来保存对象的年龄值,避免了浅拷贝带来的问题。然后释放原有内存,确保不会发生内存泄漏。

        在 test01() 函数中,创建了三个 Person 对象 p1p2 和 p3,分别表示年龄为 18、20 和 30 岁的人。然后进行了赋值操作 p3 = p2 = p1;,这里演示了连续的赋值操作。

        最后输出了每个人的年龄。

注:

/* c++编译器至少给一个类添加4个函数
    1. 默认构造函数(无参,函数体为空)
    2. 默认析构函数(无参,函数体为空)
    3. 默认拷贝构造函数,对属性进行值拷贝
    4. 赋值运算符 operator=, 对属性进行值拷贝

    如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题

    开辟堆区   使用 new 数据类型
*/

#include <iostream>
using namespace std;


class Person
{
public:

	Person(int age)   //有参构造函数
	{
		m_Age = new int(age);   //  new int()  返回的就是 int *
	}

	~Person()
	{
		if (m_Age != NULL)
		{
			delete m_Age;
			m_Age = NULL;
		}
	}

	// 重载赋值运算符
	Person & operator=(Person &p)
	{
		// 编译器提供是浅拷贝
		// m_Age = p.m_Age

		// 深拷贝解决
		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(18);

	Person p2(20);
    

	/*  如果说还需要做出一个赋值操作,此时,应该再返回的函数那里修改,返回的应该是变量本身
	*/
	Person p3(30);

    p3 =p2 = p1;  //赋值操作


    cout << "p1的年龄 : " << *p1.m_Age << endl;

	cout << "p2的年龄 : " << *p2.m_Age << endl;
	cout << "p3的年龄 : " << *p3.m_Age << endl;

}


int main()
{

	test01();


	system("pause");
	return 0;
}

        示例运行结果如下图所示:

06-关系运算符重载       

        关系运算符(比较运算符)重载允许定义类对象之间的比较操作的行为,使得对象之间可以像内置类型一样进行比较。这些运算符包括等于(==)、不等于(!=)、大于(>)、小于(<)、大于等于(>=)和小于等于(<=)。

        在C++中,可以通过在类内部或类外部定义特定的成员函数或全局函数来重载关系运算符。以下是分别在类内部和类外部重载关系运算符的方法。

        在类内部重载关系运算符:在这里,我们以重载等于运算符(==)为例。operator== 是关系运算符的重载函数。它接受一个常量引用作为参数,即右操作数,然后比较两个对象是否相等,并返回布尔值表示比较结果。

class ClassName {
public:
    bool operator==(const ClassName& rhs) const {
        // 比较对象是否相等,并返回结果
    }

    // 重载其他关系运算符
};

        在类外部重载关系运算符:在这里,我们以重载等于运算符(==)为例。operator== 是关系运算符的重载函数。它接受两个参数,分别是左操作数和右操作数,然后比较两个对象是否相等,并返回布尔值表示比较结果。

bool operator==(const ClassName& lhs, const ClassName& rhs) {
    // 比较两个对象是否相等,并返回结果
}

        下面是一个具体的例子,展示了如何在类中重载等于运算符:在这个例子中,MyNumber 类重载了等于运算符(==),以支持对象之间的相等性比较。在重载函数中,它比较了两个对象的 value 成员是否相等,并返回比较结果。

class MyNumber {
private:
    int value;

public:
    MyNumber(int val) : value(val) {}

    bool operator==(const MyNumber& rhs) const {
        return this->value == rhs.value;
    }
};

        下面给出具体代码分析应用过程,这段代码演示了如何在类中重载关系运算符(==),并实现了自定义的对象相等性比较。代码解释如下:

        定义了一个名为 Person 的类,其中包含两个成员变量 m_Name 和 m_Age,分别表示人的姓名和年龄。

        类中提供了一个构造函数,用于初始化 m_Name 和 m_Age 成员。

        在类中重载了等于运算符 operator==。在重载函数中,通过比较两个 Person 对象的 m_Name 和 m_Age 成员是否相等,来判断两个对象是否相等,并返回相应的布尔值。

        在 test01() 函数中,创建了两个 Person 对象 p1 和 p2,它们的姓名和年龄都相同。然后通过 if (p1 == p2) 来判断它们是否相等,并输出相应的结果。

        最后输出了判断结果。

#include <iostream>
using namespace std;

// 重载关系运算符

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;

};

void test01()
{
	Person p1("张三", 18);
	Person p2("张三", 18);

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

int main()
{
	test01();

	system("pause");
	return 0;
}

        示例运行结果如下图所示:

07-函数调用运算符重载       

       函数调用运算符(也称为仿函数或函数对象)允许你将对象像函数一样调用,这样你可以像调用函数一样使用对象。在C++中,你可以通过在类中重载函数调用运算符 operator() 来实现这一点。

        下面是重载函数调用运算符的一般形式:在这里,Functor 是函数对象的类名,ReturnType 是调用运算符返回的类型,ParameterType1ParameterType2 等是调用运算符接受的参数类型。

class Functor {
public:
    ReturnType operator()(ParameterType1 arg1, ParameterType2 arg2, ...) {
        // 函数体
    }
};

        具体的例子来解释:在这个例子中,MyFunctor 类重载了函数调用运算符 operator()。在 operator() 函数中,它输出传入的参数。在 main 函数中,我们创建了一个 MyFunctor 类的对象 myFunc,然后像调用函数一样使用该对象,并传入参数 10

#include <iostream>
using namespace std;

class MyFunctor {
public:
    void operator()(int x) {
        cout << "Function called with argument: " << x << endl;
    }
};

int main() {
    MyFunctor myFunc;

    // 将对象 myFunc 像调用函数一样调用
    myFunc(10);

    return 0;
}

        下面给出具体代码分析应用过程,这段代码演示了如何使用函数调用运算符重载,也称为仿函数(functor)。代码解释如下:

        首先定义了一个名为 MyPrint 的类,它实现了函数调用运算符 operator()。在 operator() 函数中,它接受一个 string 类型的参数 text,然后将该参数输出到标准输出流中。

        在 test01() 函数中,创建了一个 MyPrint 类的对象 myFunc,然后像调用函数一样使用该对象,并传入字符串参数 "hello world"。这样就会调用 MyPrint 类中重载的函数调用运算符,输出 "hello world" 到标准输出流中。

        接着定义了一个名为 MyAdd 的类,它也实现了函数调用运算符 operator()。在 operator() 函数中,它接受两个 int 类型的参数 v1 和 v2,然后返回它们的和。

        在 test02() 函数中,创建了一个 MyAdd 类的对象 add,然后像调用函数一样使用该对象,并传入整数参数 10 和 10。这样就会调用 MyAdd 类中重载的函数调用运算符,计算并返回 10 + 10 的结果,最后输出到标准输出流中。

        还展示了匿名对象调用的方式,通过 MyAdd()(100, 100) 这样的形式,直接创建一个 MyAdd 类的匿名对象,并调用其函数调用运算符,并传入整数参数 100 和 100,以此来计算并输出结果。

#include <iostream>
using namespace std;
#include <string>

class MyPrint
{
public:
	void operator()(string text)
	{
		cout << text << endl;
	}
};

void test01()
{
	//重载的()操作符 也称为仿函数
	MyPrint myFunc;
	myFunc("hello world");
}

class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
	
};

void test02()
{
	MyAdd add;
	int ret = add(10, 10);
	cout << "ret = " << ret << endl;
	//匿名对象调用
	cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}

int main() {

	test01();
	test02();
	system("pause");
	return 0;
}

        示例运行结果如下图所示:

总结       

        运算符重载是C++中一个强大的特性,它允许你重新定义运算符的行为,使得它们能够用于自定义类型的对象上。下面是一些运算符重载的总结:

        语法:运算符重载是通过定义一个成员函数或全局函数来完成的,其函数名是 operator 后接要重载的运算符符号。例如,operator+ 用于重载加法运算符。

        成员函数 vs 全局函数:你可以选择将运算符重载定义为类的成员函数或全局函数。成员函数的左操作数是调用对象,而全局函数的左操作数是第一个参数。

        返回类型:对于大多数运算符,重载函数应该返回一个值,通常是引用类型以支持连续操作。

        参数:运算符重载函数的参数取决于运算符本身的操作数。一元运算符可能只有一个参数,而二元运算符可能有两个参数。

        一元运算符 vs 二元运算符:一元运算符只作用于一个操作数,如递增运算符(++);而二元运算符作用于两个操作数,如加法运算符(+)。

        重载示例:常见的运算符重载包括加法、减法、乘法、除法、赋值、递增、递减、等于、不等于等。重载它们可以使得自定义类型的对象能够像内置类型一样使用这些运算符。

        注意事项:在重载运算符时,需要遵循运算符的基本语义,以确保代码的清晰性和可预测性。同时,避免过度使用运算符重载,以免导致代码难以理解。

        友元函数:有时候需要在类外部重载运算符并访问类的私有成员,可以将重载函数声明为类的友元函数。

        总的来说,运算符重载是C++中的一个强大工具,能够提高代码的可读性和灵活性,但也需要谨慎使用,遵循良好的编程实践。

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一伦明悦

感谢,您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值