首页 > 编程语言 >【C++基础】多种函数重载和运算符重载

【C++基础】多种函数重载和运算符重载

时间:2024-08-28 20:53:42浏览次数:6  
标签:函数 int C++ 运算符 ++ Complex 重载

目录

一、函数重载

1. 参数类型不同的重载

讲解

2. 参数个数不同的重载

讲解

3. 参数顺序不同的重载

讲解

4. 默认参数与函数重载

讲解

二、运算符重载

1. 运算符重载的基本语法

示例讲解

函数内部的操作:

运算符的使用:

2. 运算符重载的常见用法

2.1 重载 << 和 >> 运算符(用于输入输出)

示例讲解

重载 << 运算符:

重载 >> 运算符:

在 main 函数中的使用:

2.2 重载 ++ 和 -- 运算符(用于自增自减)

示例讲解

构造函数:

前置 ++ 运算符重载:

后置 ++ 运算符重载:

显示当前计数值:

在 main 函数中的使用:

3. 重载运算符的注意事项

4. 重载运算符时的规则

三、扩展

问题1:如何区分对象创建时,调用的是构造函数还是赋值重载函数?

1. 构造函数

2. 赋值操作符

示例解析

构造函数

赋值操作符

关键区别

如需咨询请添加个人微信:a15135158368

欢迎叨扰,多多交流

一、函数重载

函数重载(Function Overloading)允许在同一个作用域内定义多个同名函数,但这些函数必须有不同的参数列表(即参数的类型、个数或顺序不同)。

通过函数重载,C++程序可以根据传入参数的不同选择相应的函数来执行。

1. 参数类型不同的重载

#include <iostream>
​
// 重载函数,根据不同类型的参数执行不同的操作
int add(int a, int b) {
    return a + b;
}
​
double add(double a, double b) {
    return a + b;
}
​
int main() {
    int int_result = add(3, 4);         // 调用的是int版本的add
    double double_result = add(3.5, 2.5); // 调用的是double版本的add
​
    std::cout << "int add result: " << int_result << std::endl;
    std::cout << "double add result: " << double_result << std::endl;
​
    return 0;
}

讲解

  • 上面的代码中,函数 add 被重载了两次,一次用于处理 int 类型参数,另一次用于处理 double 类型参数。

  • 当调用 add(3, 4) 时,编译器根据传递的参数类型选择 int 版本的 add,而当调用 add(3.5, 2.5) 时,编译器则选择 double 版本的 add

2. 参数个数不同的重载

#include <iostream>
​
// 重载函数,根据参数个数不同执行不同操作
int multiply(int a, int b) {
    return a * b;
}
​
int multiply(int a, int b, int c) {
    return a * b * c;
}
​
int main() {
    int result1 = multiply(2, 3);       // 调用的是两个参数版本的multiply
    int result2 = multiply(2, 3, 4);    // 调用的是三个参数版本的multiply
​
    std::cout << "multiply(2, 3): " << result1 << std::endl;
    std::cout << "multiply(2, 3, 4): " << result2 << std::endl;
​
    return 0;
}

讲解

  • 在这个例子中,multiply 函数被重载了两次,一次是两个参数版本,一次是三个参数版本。

  • 当调用 multiply(2, 3) 时,编译器选择两个参数版本的 multiply,而调用 multiply(2, 3, 4) 时,编译器选择三个参数版本的 multiply

3. 参数顺序不同的重载

#include <iostream>
​
// 重载函数,根据参数顺序不同执行不同操作
void display(int a, double b) {
    std::cout << "int and double: " << a << " " << b << std::endl;
}
​
void display(double b, int a) {
    std::cout << "double and int: " << b << " " << a << std::endl;
}
​
int main() {
    display(3, 4.5);    // 调用的是int, double版本的display
    display(4.5, 3);    // 调用的是double, int版本的display
​
    return 0;
}

讲解

  • 在这个例子中,函数 display 被重载了两次,两次的参数类型相同,但顺序不同。

  • 当调用 display(3, 4.5) 时,编译器选择 int, double 顺序版本,而调用 display(4.5, 3) 时,编译器选择 double, int 顺序版本。

4. 默认参数与函数重载

#include <iostream>
​
// 重载函数以及带有默认参数的函数
void printMessage(std::string message, int times = 1) {
    for (int i = 0; i < times; ++i) {
        std::cout << message << std::endl;
    }
}
​
void printMessage(std::string message, double times) {
    std::cout << "Message: " << message << ", repeated " << times << " times." << std::endl;
}
​
int main() {
    printMessage("Hello");          // 调用的是带默认参数的int版本的printMessage
    printMessage("Hello", 3);       // 调用的是int版本的printMessage
    printMessage("Hello", 2.5);     // 调用的是double版本的printMessage
​
    return 0;
}

讲解

  • 在这个例子中,printMessage 函数被重载了两次,一次接受 inttimes 参数,并且 times 有默认值,另一次接受 doubletimes 参数。

  • 当调用 printMessage("Hello") 时,编译器选择第一个版本,且使用默认参数 times = 1

  • 当调用 printMessage("Hello", 3) 时,编译器选择第一个版本,因为传递的 3int 类型。

  • 当调用 printMessage("Hello", 2.5) 时,编译器选择第二个版本,因为传递的 2.5double 类型。

二、运算符重载

在C++中,运算符重载允许程序员为用户自定义的类型(如类或结构体)定义新的运算符行为。这意味着可以对类对象使用像 +-* 等运算符,类似于对内置类型(如 intfloat 等)进行操作。

简单的来说,就是将变量使用的运算符重载为了对象使用。

1. 运算符重载的基本语法

运算符重载通过在类中定义一个特殊的成员函数或友元函数来实现。

重载函数的函数名为 operator 后跟要重载的运算符。例如:

#include <iostream>
​
class Complex {
private:
    double real;
    double imag;
​
public:
    // 构造函数
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
​
    // 重载加法运算符
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
​
    // 显示复数
    void display() const {
        std::cout << "(" << real << " + " << imag << "i)" << std::endl;
    }
};
​
int main() {
    Complex c1(3.0, 4.0); // 创建复数 c1 = 3 + 4i
    Complex c2(1.0, 2.0); // 创建复数 c2 = 1 + 2i
​
    // 使用重载的加法运算符
    Complex c3 = c1 + c2;
​
    // 显示结果
    std::cout << "c1 = "; c1.display();
    std::cout << "c2 = "; c2.display();
    std::cout << "c1 + c2 = "; c3.display();
​
    return 0;
}
c1 = (3 + 4i)
c2 = (1 + 2i)
c1 + c2 = (4 + 6i)

示例讲解

  1. 重载加法运算符的定义

    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    • operator+ 是我们定义的一个函数,用于重载 + 运算符。

    • const Complex& other 是该函数的参数,表示加号右边的复数对象。使用 const 表明我们不会修改传入的对象,使用引用是为了避免不必要的拷贝操作。

    • const 放在函数末尾,表明这个函数不会修改调用该函数的对象内部的成员变量。

    • 函数的返回类型是 Complex,即返回一个新的复数对象。

  2. 函数内部的操作
    return Complex(real + other.real, imag + other.imag);
    • real + other.real 表示将当前对象的实部与 other 的实部相加。

    • imag + other.imag 表示将当前对象的虚部与 other 的虚部相加。

    • 最后返回一个新的 Complex 对象,它的实部和虚部分别是上述两个相加的结果。

  3. 运算符的使用
    Complex c3 = c1 + c2;
    • 当我们编写 c1 + c2 时,编译器会调用 operator+ 函数。

    • c1 是调用对象,因此 realimagc1 的成员。

    • c2 是传入的参数对象(即 other),其实部和虚部用于与 c1 的对应部分相加。

    • 返回的新对象 c3 包含了相加后的实部和虚部。

通过这个重载,我们可以像处理内置类型一样,直接对 Complex 对象使用 + 运算符,从而使代码更具可读性和直观性。

2. 运算符重载的常见用法

2.1 重载 <<>> 运算符(用于输入输出)

#include <iostream>

class Complex {
private:
    double real;
    double imag;

public:
    // 构造函数
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

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

    // 重载输出运算符 <<
    friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
        os << "(" << c.real << " + " << c.imag << "i)";
        return os;
    }

    // 重载输入运算符 >>
    friend std::istream& operator>>(std::istream& is, Complex& c) {
        is >> c.real >> c.imag;
        return is;
    }
};

int main() {
    Complex c1, c2;

    // 从输入流读取复数
    std::cout << "输入第一个复数(实部和虚部): ";
    std::cin >> c1;

    std::cout << "输入第二个复数(实部和虚部): ";
    std::cin >> c2;

    // 使用重载的加法运算符
    Complex c3 = c1 + c2;

    // 使用重载的输出运算符显示结果
    std::cout << "c1 = " << c1 << std::endl;
    std::cout << "c2 = " << c2 << std::endl;
    std::cout << "c1 + c2 = " << c3 << std::endl;

    return 0;
}
输入第一个复数(实部和虚部): 3 4
输入第二个复数(实部和虚部): 1 2
c1 = (3 + 4i)
c2 = (1 + 2i)
c1 + c2 = (4 + 6i)
示例讲解
  1. 重载 << 运算符:
       // 重载输出运算符 <<
    friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
        os << "(" << c.real << " + " << c.imag << "i)";
        return os;
    }
        //std::cout << "输入第一个复数(实部和虚部): ";
    • operator<< 是一个友元函数,它重载了 << 运算符,使我们可以将 Complex 对象直接输出到输出流(如 std::cout)。

    • std::ostream& os 是输出流对象的引用,用于表示输出的目标(例如,控制台)。

    • const Complex& c 是要输出的复数对象。

    • 在函数内部,使用 os << 将复数的格式化字符串输出到流中。最后返回 os 以支持链式操作。

  2. 重载 >> 运算符:
       // 重载输入运算符 >>
    friend std::istream& operator>>(std::istream& is, Complex& c) {
        is >> c.real >> c.imag;
        return is;
    }
        //std::cin >> c2;
    • operator>> 是另一个友元函数,重载了 >> 运算符,使我们可以从输入流(如 std::cin)读取 Complex 对象。

    • std::istream& is 是输入流对象的引用,用于表示输入的来源(例如,键盘)。

    • Complex& c 是要输入的复数对象的引用。

    • 在函数内部,使用 is >> 依次读取实部和虚部,并将它们存储到 c 的成员变量中。最后返回 is 以支持链式操作。

  3. main 函数中的使用:
    • 首先,提示用户输入两个复数的实部和虚部,使用 >> 运算符读取这些值。

    • 然后,使用重载的 + 运算符将两个复数相加。

    • 最后,使用 << 运算符将结果输出到控制台。

通过重载 <<>> 运算符,我们可以直接使用标准的输入输出方式来处理 Complex 对象,使得代码更为简洁易读。

2.2 重载 ++-- 运算符(用于自增自减)

#include <iostream>

class Counter {
private:
    int count;

public:
    // 构造函数
    Counter(int c = 0) : count(c) {}

    // 前置++运算符
    Counter& operator++() {
        ++count;  // 先自增,再返回自身的引用
        return *this;
    }

    // 后置++运算符
    Counter operator++(int) {
        Counter temp = *this; // 保存当前状态
        ++count;               // 自增
        return temp;           // 返回保存的未自增前的状态
    }

    // 显示当前计数值
    void display() const {
        std::cout << "Count: " << count << std::endl;
    }
};

int main() {
    Counter c1(5);  // 创建一个初始值为5的Counter对象

    // 使用前置自增运算符
    std::cout << "使用前缀 ++:" << std::endl;
    ++c1;
    c1.display();   // 显示 c1 的当前值

    // 使用后置自增运算符
    std::cout << "使用后缀 ++:" << std::endl;
    c1++;
    c1.display();   // 显示 c1 的当前值

    return 0;
}
使用前缀 ++:
Count: 6
使用后缀 ++:
Count: 7
示例讲解
  1. 构造函数
    Counter(int c = 0) : count(c) {}
    • 这是一个构造函数,用于初始化 Counter 对象。如果不提供参数,count 将默认被初始化为 0。

  2. 前置 ++ 运算符重载
    Counter& operator++() {
        ++count;
        return *this;
    }
    //    ++c1;
    • 这是前置自增运算符的重载。前置自增先增加对象的 count 值,然后返回对象本身的引用(即 *this)。

    • 返回引用的原因是为了支持连续的操作,如 ++(++c1);

  3. 后置 ++ 运算符重载
    Counter operator++(int) {
        Counter temp = *this;
        ++count;
        return temp;
    }
    //    c1++;
    • 这是后置自增运算符的重载。后置自增需要传递一个整型参数 int,用于区分它与前置自增运算符。该参数并不实际使用。

    • 后置自增首先将当前对象的状态保存到 temp 中,然后增加 count 的值,最后返回未自增前的对象 temp

  4. 显示当前计数值
    void display() const {
        std::cout << "Count: " << count << std::endl;
    }
    • 这个成员函数输出当前计数器的值。函数末尾的 const 表示该函数不会修改类的成员变量。

  5. main 函数中的使用
    • 首先,创建了一个初始值为 5 的 Counter 对象 c1

    • 使用 ++c1 触发前置自增运算符。count 值从 5 增加到 6,并显示结果。

    • 使用 c1++ 触发后置自增运算符。count 值先从 6 增加到 7,然而返回的是未增加前的状态。因此显示的结果仍然是 6。在显示完成后,count 实际上已变为 7

3. 重载运算符的注意事项

  • 运算符必须是类的成员函数或友元函数

    有些运算符必须作为成员函数实现,如 =[]()->

    而有些运算符可以作为友元函数来实现,如 +- 等。

  • 不能重载的运算符

    有一些运算符是不能重载的,包括 ::(作用域解析运算符)、.(成员访问运算符)、.*(成员指针访问运算符)、?:(条件运算符)和 sizeof(类型大小运算符)。

4. 重载运算符时的规则

  • 保持运算符的语义一致性

    重载运算符时应尽量保持其原有的语义。

    例如,重载 + 运算符时,应该实现对象之间的“加法”行为。

  • 返回类型

    运算符重载的返回类型取决于运算符的类型和预期的操作结果。

    可以返回对象、引用或指针。

  • 成员函数与友元函数的选择

    成员函数一般用于需要访问对象内部数据的运算符

    友元函数则用于需要同时访问两个对象内部数据的运算符。

三、扩展

问题1:如何区分对象创建时,调用的是构造函数还是赋值重载函数?

在 C++ 中,区分构造函数和赋值操作符是根据它们在对象生命周期中的作用和调用方式来实现的。

1. 构造函数
  • 作用:用来初始化新创建的对象。

  • 调用方式:在创建对象时调用,例如 String string3 = string1;

2. 赋值操作符
  • 作用:用来将一个已存在的对象的值赋给另一个已存在的对象。

  • 调用方式:在对象已经创建并且已被初始化之后,调用赋值操作符,例如 string4 = string1;

示例解析

构造函数
String string3 = string1;
  • 这行代码在创建 string3 对象时直接调用了构造函数。

  • 这里使用了拷贝构造函数,因为 string3 是新创建的对象,string1 是一个已经存在的对象。

赋值操作符
String string4;
string4 = string1;
  • 这两行代码首先创建了 string4 对象(使用默认构造函数),然后将 string1 的值赋给 string4

关键区别
  • 创建与赋值

    构造函数用于创建并初始化对象

    赋值操作符用于给已存在的对象赋值。

  • 调用时机

    String string3 = string1; 是在 string3 创建时发生的,调用了拷贝构造函数

    string4 = string1; 是在 string4 已存在后发生的,调用了赋值操作符。

标签:函数,int,C++,运算符,++,Complex,重载
From: https://blog.csdn.net/m0_63956046/article/details/141649128

相关文章

  • 超详细!SQL运算符的操作练习-笔记-04章:运算符
    写在前面的话(•̀.̫•́)✧即将学习数据库系统的课程,此文为预习与自学,自学配套课程链接为:MySQL数据库入门到大牛,mysql安装到优化,百科全书级,全网天花板_哔哩哔哩_bilibili时间不够可以不看,前五章内容都比较简单,纯看笔记也能学会。本文主要内容是学习和练习运算符,这......
  • 突破编程 C++ 设计模式(组合模式)详尽攻略
    在软件开发中,设计模式为程序员提供了解决特定问题的最佳实践。设计模式不仅提高了代码的可复用性和可维护性,还能帮助团队更好地进行协作。在这篇文章中,我们将深入探讨组合模式——一种结构型设计模式。组合模式允许你将对象组合成树形结构来表示“部分-整体”的层次关系。组合......
  • C++基础/C++中的多态(关于虚...)
    C++中的多态(关于虚...)1.前置基础知识1.1对象是如何存储在内存中的#include<iostream>#include<string>classAnimal{private:stringname;intage;public:Animal(std::stringname,intage):name(name),age(age){};~Animal();virtu......
  • C++基础/C++中的多态(关于虚...)
    C++中的多态(关于虚…)1.前置基础知识1.1对象是如何存储在内存中的#include<iostream>#include<string>classAnimal{private:stringname;intage;public:Animal(std::stringname,intage):name(name),age(age){};~Animal();......
  • C++基础
    指针#include<iostream>usingnamespacestd;intmain(){//实际变量的声明intvar=20;//指针变量的声明int*addr;//在指针变量中存储var的地址addr=&var;cout<<"var="<<var<<endl;//输出在指针变量中存......
  • 你可能想知道如何下载DEV C++
    DevC++是一款适用于Windows平台的C/C++集成开发环境(IDE),它由Bloodshed公司开发,但自2011年后由独立开发者Orwelldevcpp继续更新维护。它支持C和C++编程语言,提供了编写、编译、调试和执行程序所需的基本功能。以下是下载DEVC++的步骤:官方下载渠道官方网站:访问SourceForgehttps......
  • C/C++实现JSON格式数据解析
    参考文章推荐以下几篇,针对Cjson的应用写的很详细,感谢!!!https://blog.csdn.net/xiaopengX6/article/details/104629606https://liang.blog.csdn.net/article/details/86605234运用场景在做C的项目时,对方通过TCP套接字将内容按照帧头+帧体的格式发送过来,其中帧体的内容是JSON格式......
  • 高斯坐标转WGS84 GPS坐标 C#版本 python版本和C++版本 3度带进行投影 三个版本的代码
    找了很久,都没有很靠谱的版本,这个是自己从C#版本转换的另外两个版本完整代码可以用经过了对比核对计算,确保3个版本之间的计算结果是一致的C#版本:GPSPointGSXYToGPS(doubleX,doubleY,doubleL0){//X=571879.3482847388;//Y=2770741.66......
  • C++学习随笔——lock_guard和mutex的使用方法
    std::mutex和std::lock_guard是C++标准库中用于多线程同步的工具,主要用于防止多个线程同时访问共享资源,导致数据竞争问题。 std::mutex是一个用于互斥锁的类,提供了锁定(lock)和解锁(unlock)的功能。使用方法:#include<iostream>#include<thread>#include<mutex>std::......
  • C++中常用宏
    C++中会常使用到宏来进行条件编译,或设置变量1、__cplusplus:区分当前代码为C++或C//定义只在C++中才进行extern"C"的操作#ifdef__cplusplusextern"C"{#endifvoidfun(inta,intb);#ifdef__cplusplus}#endif2、区分操作系统:_WIN32:Windows操作系统,不区......