zoukankan      html  css  js  c++  java
  • C++语言-04-重载

    相关概念

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

    函数重载

    • 规则

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

      // 两个整数相加
      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;
      }
      
  • 相关阅读:
    Play Framework + ReactiveMongo 环境搭建
    阿里前端二面(笔试/机试)总结
    ES 6 新特性整理
    Javascript Dom 相关知识整理
    Ajax、CORS、Comet和WebSocket
    XHTML 1.0 标签语义
    Javascript知识整理
    Javascript性能优化(一)
    CSS知识整理
    绘制标准的d3图表
  • 原文地址:https://www.cnblogs.com/theDesertIslandOutOfTheWorld/p/5219458.html
Copyright © 2011-2022 走看看