🤓2.6 提供重载函数

函数重载机制:
定义拥有相同名称的函数,参数列表不相同(参数类型、参数个数),即为重载函数。

:::tips 一个函数不能既作为重载函数,又作为有默认参数的函数。因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,出现二义性,系统无法执行
编译器无法根据返回值的不同来区分重载函数; :::

*🐒C++ 中的运算符重载

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表
e.g. Box operator+(const Box&);

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. public:
  6. double getVolume(void)
  7. {
  8. return length * breadth * height;
  9. }
  10. void setLength( double len )
  11. {
  12. length = len;
  13. }
  14. void setBreadth( double bre )
  15. {
  16. breadth = bre;
  17. }
  18. void setHeight( double hei )
  19. {
  20. height = hei;
  21. }
  22. // 重载 + 运算符,用于把两个 Box 对象相加
  23. Box operator+(const Box& b)
  24. {
  25. Box box;
  26. box.length = this->length + b.length;
  27. box.breadth = this->breadth + b.breadth;
  28. box.height = this->height + b.height;
  29. return box;
  30. }
  31. private:
  32. double length; // 长度
  33. double breadth; // 宽度
  34. double height; // 高度
  35. };
  36. // 程序的主函数
  37. int main( )
  38. {
  39. Box Box1; // 声明 Box1,类型为 Box
  40. Box Box2; // 声明 Box2,类型为 Box
  41. Box Box3; // 声明 Box3,类型为 Box
  42. double volume = 0.0; // 把体积存储在该变量中
  43. // Box1 详述
  44. Box1.setLength(6.0);
  45. Box1.setBreadth(7.0);
  46. Box1.setHeight(5.0);
  47. // Box2 详述
  48. Box2.setLength(12.0);
  49. Box2.setBreadth(13.0);
  50. Box2.setHeight(10.0);
  51. // Box1 的体积
  52. volume = Box1.getVolume();
  53. cout << "Volume of Box1 : " << volume <<endl;
  54. // Box2 的体积
  55. volume = Box2.getVolume();
  56. cout << "Volume of Box2 : " << volume <<endl;
  57. // 把两个对象相加,得到 Box3
  58. Box3 = Box1 + Box2;
  59. // Box3 的体积
  60. volume = Box3.getVolume();
  61. cout << "Volume of Box3 : " << volume <<endl;
  62. return 0;
  63. }

小结

  • 一个函数不能既作为重载函数,又作为有默认参数的函数
  • 重载运算符是一个特殊的重载函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。

🐮2.7 定义并使用模板函数

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
模板函数(function template)的定义方式:

  1. template <typename elemType>
  2. void display_message(const string &msg, const vector<elemType> &vec)

关键字 typename 表示 elemType 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。
使用时:

  1. vector<int> ivec;
  2. string msg;
  3. //...
  4. display_message(msg, ivec)
  5. //这时,编译器会将elemType绑定为int类型;

:::info 一般而言,如果函数具有多种实现方式,我们可以将它重载,其每份实例提供的是相同的通用服务。如果我们希望让程序代码的主题不变,仅仅改变其中用到的数据类型,可以通过function template达到目的。 ::: :::tips 模板函数也可以是重载函数; :::

扩展

—-黑马编程Cpp基础
模板函数和普通函数的区别

  • 普通函数可以进行自动类型转换,而模板函数不可以

    1. template<class T>
    2. T MyPlus(T a, T b){
    3. T ret = a + b;
    4. return ret;
    5. }
    6. //普通函数
    7. int MyPlus(int a,char b){
    8. int ret = a + b;
    9. return ret;
    10. }
    11. void test02(){
    12. int a = 10;
    13. char b = 'a';
    14. //调用函数模板,严格匹配类型
    15. MyPlus(a, a);
    16. MyPlus(b, b);
    17. //调用普通函数
    18. MyPlus(a, b);
    19. //调用普通函数 普通函数可以隐式类型转换
    20. MyPlus(b, a);
    21. }
  • c++编译器优先考虑普通函数除非模板函数可以产生更好的匹配,可以通过空模板实参列表的语法限定编译器只能通过模板匹配 ;

  • 模板函数的实现机制:
    • 编译器并不是把函数模板处理成能够处理任何类型的函数
    • 函数模板通过具体类型产生不同的函数
    • 编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译
  • 模板函数的局限性:对于某些特殊的数据类型(比如自定义的)难以处理;但是可以做出专门的重载

    1. //普通交换函数
    2. template <class T>
    3. void mySwap(T &a,T &b)
    4. {
    5. T temp = a;
    6. a = b;
    7. b = temp;
    8. }
    9. //第三代具体化,显示具体化的原型和定意思以template<>开头,并通过名称来
    10. 指出类型
    11. //具体化优先于常规模板
    12. template<>void mySwap<Person>(Person &p1, Person &p2)
    13. {
    14. string nameTemp;
    15. int ageTemp;
    16. nameTemp = p1.mName;
    17. p1.mName = p2.mName;
    18. p2.mName = nameTemp;
    19. ageTemp = p1.mAge;
    20. p1.mAge = p2.mAge;
    21. p2.mAge = ageTemp;
    22. }

    小结

  • 模板函数即提供一个抽象的数据类型(模板),使得函数能够根据不同的数据类型做出相同的操作。

  • 重载是为不同实例提供相同的服务,而函数模板只是为了适应不同的数据类型