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

news2025/1/19 21:50:21

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

📜 个人主页:@一伦明悦-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++中的一个强大工具,能够提高代码的可读性和灵活性,但也需要谨慎使用,遵循良好的编程实践。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1682042.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑马guli商城项目初始化-SpringCloud微服务项目初始化使用SpringCloudAlibaba快速搭建分布式系统

视频教程&#xff1a;https://www.bilibili.com/video/BV1np4y1C7Yf?p4&spm_id_frompageDriver&vd_source0b3904471b2f8a3a133e05bd42f729a9 这里写目录标题 1.服务架构图2.初始化目录结构3.初始化数据库4.使用逆向工程项目生成数据库CRUD5.创建工具项目6.配置mybati…

CentOS7使用Docker安装Redis图文教程

1.拉取Redis镜像 这里制定了版本&#xff0c;不指定默认latest最新版 docker pull redis:6.0.8提示信息如下即为下载成功 2.上传配置文件 官方配置文件&#xff08;找自己对应的版本&#xff09;&#xff1a;reids.conf 或者将如下配置文件命名为redis.conf&#xff0c;上…

面试题草稿

目录 一&#xff0e;JAVA基础 1.八个基本数据类型&#xff0c;长&#xff0c;占几个字节&#xff0c;取值范围是多少。 基本类型&#xff1a; 2.面向对象的特征 1. 封装&#xff08;Encapsulation&#xff09; 3.实现多态的几种方式 4.什么叫装箱什么叫拆箱 5.装拆箱分别…

Nginx启动关闭重启用脚本实现

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 Nginx(“engine x”…

快手截流多功能协议引流多线程多账号使用

在市场上&#xff0c;类似的软件售价都在几千元&#xff0c;但我发现这款全新版本的软件已经更新&#xff0c;而且我只需要配合使用谷歌浏览器&#xff0c;稍微调慢一点延时&#xff0c;我就可以像专业人士一样流畅地进行操作。 评论对于我而言是一种艺术&#xff0c;而不仅仅是…

植物大战僵尸杂交版(含下载方式)

最近时间&#xff0c;一款很火的植物大战僵尸杂交版火爆出圈&#xff0c;在玩家之间疯狂扩散。各种奇特的杂交组合让游戏变得更加有趣。 游戏介绍 植物大战僵尸杂交版是一款将《植物大战僵尸》和植物杂交概念结合在一起的独特塔防策略游戏。它将《植物大战僵尸》中的植物与进行…

【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置

本节博客主要是通过“在排序数组中查找元素的第一个和最后一个位置”总结关于二分算法的左右界代码模板&#xff0c;有需要借鉴即可。 目录 1.题目2.二分边界算法2.1查找区间左端点2.1.1循环条件2.1.2求中点的操作2.1.3总结 2.2查找区间右端点2.1.1循环条件2.1.2求中点的操作2.…

FebHost:为什么企业需要注册保加利亚.BG域名?

在当今全球化的商业环境中&#xff0c;对于与保加利亚市场息息相关的企业而言&#xff0c;选择合适的域名至关重要。.BG域名作为企业在线身份的重要组成部分&#xff0c;提供了多重利好&#xff0c;成为业内不容忽视的战略资源。 首先&#xff0c;地域标识性强是.BG域名的一大…

ArrayList和LinkedList的使用

ArrayList List<> list new ArrayList<>(); LinkedList

深入理解 House of Cat

Index 序言利用 FSOP 调用 House of Cat利用条件伪造IO流条件完整调用链分析 模板System (one_gadget) 模板ORW模板 Demo & Exp利用 __malloc_assert 调用 House of Cat例题&#xff1a;题目思路Exp 序言 原文章&#xff1a;深入理解 House of Cat 随着 GNU 持续不断的更…

【Linux-IMX6ULL-DDR3简介测试-RGBLCD控制原理】

目录 1. DDR3 简介1.1 前要基本概念RAM & ROM 2. DDR3测试及初始化3. RGBLCD简介及控制原理3.1 RGBLCD简介3.2 RGBLCD-时序-像素时钟-显存3.2.1 RGB LCD时序3.2.2 像素时钟&#xff08;800*400分辨率&#xff09;3.2.2 显存&#xff08;800*400分辨率&#xff09; 3.3 RGBL…

Spring注解解析:条件注解@Condition注解和@ConditonOnXXX注解

文章目录 一、条件注解二、Conditional1、使用方法2、示例 一、条件注解 条件注解的作用是给需要装载的Bean增加一个条件判断。只有满足条件才会装在到IoC容器中。而这个条件可以由自己去完成的&#xff0c;可以通过重写Condition接口重写matches()方法去实现自定义的逻辑。所…

.NET 分享一款Web打包和解压缩工具

01本文概要 在.NET部署环境中&#xff0c;利用IIS中间件开启对ASP的支持&#xff0c;可以实现许多强大的文件操作功能。特别是在一些需要进行预编译的情况下&#xff0c;通过上传ASP脚本&#xff0c;可以获得WebShell&#xff0c;从而方便地进行各种操作。本文将介绍一个名为S…

运动耳机怎么选?五款新手必买的运动耳机盘点

运动耳机是专为运动爱好者设计的耳机&#xff0c;轻巧便携&#xff0c;佩戴稳固。无论你在跑步、健身还是骑行&#xff0c;它都能为你带来优质的音乐体验。那如何选择一款合适的运动耳机呢&#xff1f;这里&#xff0c;我结合自己和身边朋友平时选购经验&#xff0c;整理了一些…

sklearn机器学习编程练习大全(二)

sklearn机器学习编程练习大全&#xff08;二&#xff09; 第11题 从字符串提取标签第12题 IRIS数据集探索第13题 构建模型&#xff0c;计算准确率第14题 预估目标列编码第15题 one-hot编码 第11题 从字符串提取标签 DataFrame如下&#xff1a; 如何将以上的DataFrame变成如下的…

python批量生成25位数字字母混合序列号(SN码)

欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.代码 三.使用 四.分析 一.前言 SN码,即Serial Number的缩写,有时也被称为Serial No,是产品序列号的意思。它是一个独特的标识符,用于区分同一种类

第二证券资讯|昨夜,黄金大涨、美股创新高!人民币狂拉

受降息预期影响&#xff0c;美股三大指数团体创新高&#xff0c;黄金期现价格亦大幅走高。 当地时间5月15日星期三&#xff0c;美股三大股指全线收涨。道指涨0.88%&#xff0c;纳指涨1.40%&#xff0c;标普500指数涨1.17%。 经济数据方面。美国4月CPI同比上涨3.4%&#xff0c…

每日一练 2025.5.16

题目&#xff1b; 给定一个非负整数&#xff0c;你至多可以交换一次数字中的任意两位。返回你能得到的最大值。 示例 1 : 输入: 2736 输出: 7236 解释: 交换数字2和数字7。示例 2 : 输入: 9973 输出: 9973 解释: 不需要交换。注意: 给定数字的范围是 [0, 108] 解题&#…

首战告捷!KCM Trade漂移队出征2024日本漂移锦标赛(FDJ2)

卓越之姿&#xff0c;非凡之势&#xff01;KCM Trade漂移队以实力点燃激情 当激情与速度交织&#xff0c;当硝烟四起的战场转移到赛车领域&#xff0c;我们见证了一场精彩绝伦、实力与策略并存的较量——KCM Trade漂移队在2024日本漂移锦标赛&#xff08;FDJ2&#xff09;上展现…

AIGC文生视频:Sora模型报告总结

作为世界模拟器的视频生成模型 我们探索视频数据生成模型的大规模训练。具体来说&#xff0c;我们在可变持续时间、分辨率和宽高比的视频和图像上联合训练文本条件扩散模型。我们利用对视频和图像潜在代码的时空补丁进行操作的变压器架构。我们最大的模型 Sora 能够生成一分钟…