相关概念

  • 重载

    • 在同一作用域中为某个函数和运算符指定多个定义,分别成为函数重载和运算符重载
  • 重载声明
    • 与之前已经在作用域内声明过的函数或方法具有相同名称的声明,参数列表和定义不同
  • 重载决策
    • 调用一个重载函数或重载运算符时,编译器需要比较调用函数时的参数类型与定义时的参数类型,来选择最合适的重载函数和重载运算符,这个过程称为重载决策

函数重载

  • 规则

    • 函数名相同
    • 参数列表不同
    • 与返回类型无关
  • 示例

    // 两个整数相加
    int sum(int a, int b) {
    cout << "sum of two int number: " << a + b << endl;
    return a + b;
    }
    // 两个双精度小数相加
    double sum(double a, double b) {
    cout << "sum of two double number: " << a + b << endl;
    return a + b;
    }
    int main(int argc, const char * argv[]) {
    sum(1, 2); // 两个整数相加
    sum(1.0, 2.0); // 两个双精度小数相加
    sum(1, 2.0); //Call to 'sum' is ambiguous
    return 0;
    }

运算符重载

  • 运算符的实质

    • 带有特殊名称的函数
  • 不可重载的运算符

    运算符 含义
    :: 作用于解析运算符
    .* 成员对象选择运算符
    . 以对象方式访问成员运算符
    ?: 条件判断运算符
  • 示例

    • 一元运算符++

      • 具有前缀形式和后缀形式,前缀形式的运算符重载函数没有参数,后缀形式的运算符重载函数具有参数
      // 创建一个Apple的类
      class AppleBasket {
      private:
      double appleWeight; // 苹果的重量
      double priceOfPerKg; // 每千克苹果的价格
      double totalPrices; // 苹果的总价格
      public:
      // set、get方法
      void setAppleWeight(double weight) {
      appleWeight = weight;
      }
      double getAppleWeight() {
      return appleWeight;
      }
      void setPriceOfPerKg(double price) {
      priceOfPerKg = price;
      }
      double getPriceOfPerKg() {
      return priceOfPerKg;
      }
      double getTotalPrices() {
      if (totalPrices == 0) { // 不打折
      totalPrices = appleWeight * priceOfPerKg;
      }
      return totalPrices;
      }
      // 构造方法
      AppleBasket() {
      appleWeight = 0;
      priceOfPerKg = 0;
      }
      AppleBasket(double priceOfPer, double weight) {
      appleWeight = weight;
      priceOfPerKg = priceOfPer;
      }
      // 运算符重载
      /** 一筐苹果的重量自增 */
      AppleBasket operator++() { // 前缀
      AppleBasket apple;
      apple.appleWeight = ++this->appleWeight;
      apple.priceOfPerKg = this->priceOfPerKg;
      return apple;
      }
      AppleBasket operator++(int) { // 后缀,参数必须是int
      AppleBasket apple = *this;
      this->appleWeight++;
      return apple;
      }
      };
    • 二元运算符+

      /** 两筐苹果的重量相加 */
      AppleBasket operator+(AppleBasket other) {
      AppleBasket apple;
      apple.appleWeight = this->appleWeight + other.appleWeight;
      apple.priceOfPerKg = this->priceOfPerKg;
      return apple;
      }
    • 赋值运算符=

      • 通常用来创建一个新的对象
      /** 赋值运算符 */
      void operator=(AppleBasket other) {
      appleWeight = other.appleWeight;
      priceOfPerKg = other.priceOfPerKg;
      }
    • 逻辑运算符<

      /** 比较this框苹果的重量是否小于other框苹果的质量 */
      bool operator<(AppleBasket other) {
      if (this->appleWeight < other.appleWeight) {
      return true;
      } else {
      return false;
      }
      }
    • 函数调用运算符

      • 不是创建一种新的函数调用方式
      • 实际上是创建了一个可以传递任意数目参数的运算符函数
      /** 函数调用运算符 */
      AppleBasket operator()(double w, double p, double totalP) {
      AppleBasket apple;
      apple.appleWeight = w;
      apple.priceOfPerKg = p;
      apple.totalPrices = totalP;
      return apple;
      }
    • 类成员访问运算符->

      • 通常用于为一个类赋予“指针”行为
      • 重载的运算符函数,必须是一个成员函数,且返回类型必须是指针或者类的对象
      • 运算符->通常与指针引用运算符*结合使用,用来实现“智能指针”的功能,通过智能指针访问对象,可以执行与普通指针不同的任务
      // Apple类的容器
      class AppleBasketContainer {
      private:
      vector<AppleBasket *> container;
      public:
      void add(AppleBasket *apple) {
      container.push_back(apple);
      }
      // 友元类
      friend class SmartPointer;
      };
      //AppleBasketContainer类的友元类
      class SmartPointer {
      private:
      AppleBasketContainer appleContainer;
      int index;
      public:
      // 构造函数
      SmartPointer(AppleBasketContainer& ac) {
      appleContainer = ac;
      index = 0;
      }
      // 运算符重载
      /** 返回值表示列表结束 */
      bool operator++() { // 前缀版本
      if (index > appleContainer.container.size()) return false;
      if (appleContainer.container[++index] == 0) return false;
      return true;
      }
      bool operator++ (int) { // 后缀版本
      return operator++();
      }
      /** 重载运算符 -> */
      Apple* operator->() {
      if (!appleContainer.container[index]) {
      cout << "Zero value!";
      return (Apple*)0;
      }
      return appleContainer.container[index];
      }
      };
    • 输入/输出运算符

      • 通常将运算符重载函数定义为友元函数,使得在不创建对象的情况下调用函数
      // 输入运算符
      friend istream &operator>>(istream &input, AppleBasket &apple) {
      cout << "请输入每kg苹果的价钱:";
      input >> apple.priceOfPerKg;
      cout << "请输入苹果的总重量:";
      input >> apple.appleWeight;
      apple.totalPrices = apple.appleWeight * apple.priceOfPerKg;
      return input;
      }
      // 输出运算符
      friend ostream &operator<<(ostream &output, const AppleBasket &apple) {
      output << "每kg苹果的价格为:" << apple.priceOfPerKg << endl;
      output << "苹果的总重量为:" << apple.appleWeight << endl;
      output << "苹果的总价为:" << apple.totalPrices << endl;
      return output;
      }
    • 下表运算符[]

      • 通常用来增强数组的功能,如:数组越界检查
      // 每个班级中最多的学生个数
      const int MaxStudentCountOfPerTeacher = 45;
      class Student {
      private:
      int studentId;
      int age;
      public:
      // set,get方法
      void setAge(int a) {
      age = a;
      }
      int getAge() {
      return age;
      }
      // studentId通常是自增的,不暴露set方法
      int getStudentId() {
      return studentId;
      }
      // 设置Teacher为Student的友元类,使Teacher可以访问Student的私有成员
      friend class Teacher;
      };
      class Teacher {
      private:
      Student students[MaxStudentCountOfPerTeacher];
      public:
      // 构造函数
      Teacher() {
      for (int i = 0; i < 45; i++) {
      students[i].studentId = i + 1;
      }
      }
      // 运算符重载(数组越界检查)
      Student operator[](int i) {
      if (i >= MaxStudentCountOfPerTeacher) {
      cout << "Index out of bounds" << endl;
      return students[0];
      }
      return students[i];
      }
      };
  • 重载运算符的简单使用

    // 重载运算符的使用示例
    int main(int argc, const char * argv[]) {
    const int size = 10;
    AppleBasket apples[size];
    AppleContainer appleContainer;
    // 初始化apples与appleContainer
    for (int i = 0; i < size; i++) {
    apples[i].setAppleWeight(i);
    apples[i].setPriceOfPerKg(8.8);
    appleContainer.add(&apples[i]);
    }
    // 创建一个迭代器
    SmartPointer smartPointer(appleContainer);
    do {
    double totalPrice = smartPointer->getTotalPrices();
    cout << "苹果的总价格为:" << totalPrice << endl;
    } while (smartPointer++);
    // 自增运算符++(前缀)
    cout << "第一筐苹果的总价格为:" << (++apples[0]).getTotalPrices() << endl;
    // 自增运算符++(后缀)
    cout << "第二筐苹果的总价格为:" << (apples[0]++).getTotalPrices() << endl;
    // 运算符+
    cout << "前两筐苹果的总价为:" << (apples[0] + apples[1]).getTotalPrices() << endl;
    // 逻辑运算符<
    if (apples[0] < apples[1]) {
    cout << "第一筐苹果的重量小于第二筐苹果的重量" << endl;
    } else {
    cout << "第一筐苹果的重量大于等于第二筐苹果的重量" << endl;
    }
    // 赋值运算符=
    AppleBasket apple = apples[2];
    cout << "第三筐苹果的重量为:" << apple.getAppleWeight() << endl;
    // 函数调用运算符()
    cout << "3kg苹果打折后的价格为:" << apple(3, 8.8, 20.0).getTotalPrices() << endl;
    // 输入输出运算符<<,>>
    cin >> apple;
    cout << apple;
    // 下标运算符[]
    Teacher teacher;
    Student student;
    student = teacher[MaxStudentCountOfPerTeacher - 1];
    cout << "最后一个学生的学号为:" << student.getStudentId() << endl;
    student = teacher[MaxStudentCountOfPerTeacher];
    cout << student.getStudentId() << endl;
    return 0;
    }

C++语言-04-重载的更多相关文章

  1. ActionScript语言函数重载

    更新:你见过JavaScript支持重载吗,规范就是这么定义的.如果不是研究Java和Flex对象的Serialization,我也不会注意它. 距离写这篇文章已有8年了,时光匆匆啊,今天整理资料时看 ...

  2. C语言-04函数

    1.参数 参数注意点 1.形式参数:定义函数时函数名后面中的参数,简称形参 2.实际参数:调用函数式传入的具体数据,简称实参 3.实参个数必须等于形参个数 4.函数体内部不能定义和形参一样的变量 5. ...

  3. C#语言-04.OOP基础

    a. OOP:面对对象思想 i. 类:是一种功能强大的数据类型,而且是面向对象的基础 . 语法:访问修饰符 class 类名{ //类的主体 } . 成员变量:不以“函数”形式体现 a. 常量:代表与 ...

  4. C语言 04 进制

    %d 或者%i 十进制 %c 输出字符 %p 输出地址 %f 输出小数 %o 八进制 %x 十六进制 一个int类型变量占4字节,占32bit(位) 例子:十进制 int=12  转二进制 0000 ...

  5. 重学C语言---04字符串和格式化输入/输出

    1.程序示例 //talkback.c一个能为你提供一些信息的对话框 #include <stdio.h> #include <string.h> //提供strlen函数原型 ...

  6. Javascript函数重载,存在呢—还是存在呢?

    1.What's is 函数重载? );//Here is int 10 print("ten");//Here is string ten } 可以发现在C++中会根据参数的类型 ...

  7. C语言面试题汇总之一

    C语言面试题汇总之一 1.static有什么用途?(请至少说明两种) l 限制变量的作用域: 设置变量的存储域. 2.引用和指针有什么区别? 引用必须被初始化,指针不必: 引用初始化以后不能被改变,指 ...

  8. javascript arguments与javascript函数重载

    1.所 有的函数都有属于自己的一个arguments对象,它包括了函所要调用的参数.他不是一个数组,如果用typeof arguments,返回的是’object’.虽然我们可以用调用数据的方法来调用 ...

  9. C++ 重载操作符与转换

    <C++ Primer 4th>读书笔记 重载操作符是具有特殊名称的函数:保留字 operator 后接需定义的操作符号. Sales_item operator+(const Sales ...

  10. 【转】c++重载、覆盖、隐藏——理不清的区别

    原文网址:http://blog.sina.com.cn/s/blog_492d601f0100jqqm.html 再次把林锐博士的<高质量c++编程指南>翻出来看的时候,再一次的觉得这是 ...

随机推荐

  1. Hql查询结果动态组装 List(map),List(bean),List(list),List(set)等格式(转)

    1.//查询整个对象String hql="from Users";Query query = session.createQuery(hql);List<Users> ...

  2. DataTables 入门使用

    前言简述 DataTables是一个JavaScript类库,它操作HTML表格,改变表格CSS样式,增强表格功能使其更具有交互性. DataTables依赖于JQuery类库. 入门示例 环境:Da ...

  3. DDD:一个朋友对领域驱动的小结

    首先我在一家老板有点关系的小软件公司带领一帮工作一两年的程序员做项目,这里要特别强调的是做项目(差不多是外包,只不过客户群体比较固定),项目就是今天项目A是这个逻辑,明天项目B是那个逻辑,两者之间的业 ...

  4. 你或许不了解的C++函数调用(1)

    这篇博客名字起得可能太自大了,搞得自己像C++大牛一样,其实并非如此.C++有很多隐藏在语法之下的特性,使得用户可以在不是特别了解的情况下简单使用,这是非常好的一件事情.但是有时我们可能会突然间发现一 ...

  5. 使用C语言描述静态链表和动态链表

    静态链表和动态链表是线性表链式存储结构的两种不同的表示方式. 静态链表的初始长度一般是固定的,在做插入和删除操作时不需要移动元素,仅需修改指针,故仍具有链式存储结构的主要优点. 动态链表是相对于静态链 ...

  6. Android manifest之系统自带的permission

    Android manifest之系统自带的permission 本文描述Android系统自带的permission.点击查看:“关于permission的原始定义和说明”.点击查看:“Androi ...

  7. Java读取Excel文件的几种方法

    Java读取 Excel 文件的常用开源免费方法有以下几种: 1. JDBC-ODBC Excel Driver 2. jxl.jar 3. jcom.jar 4. poi.jar 简单介绍: 百度文 ...

  8. DOM中 property 和 attribute 详解

    被问到 property 和 attribute 的区别,想来也是要好好看一下. 一.基本概念区别 其实Attribute和Property这两个单词,翻译出来都是“属性”,<js高级程序设计& ...

  9. Winform开发框架之客户关系管理系统(CRM)的开发总结系列4-Tab控件页面的动态加载

    在前面介绍的几篇关于CRM系统的开发随笔中,里面都整合了多个页面的功能,包括多文档界面,以及客户相关信息的页面展示,这个模块就是利用DevExpress控件的XtraTabPage控件的动态加载实现的 ...

  10. ASP.NET MVC5 网站开发实践

    http://www.cnblogs.com/mzwhj/p/3538108.html