相关概念
- 重载
- 在同一作用域中为某个函数和运算符指定多个定义,分别成为函数重载和运算符重载
- 重载声明
- 与之前已经在作用域内声明过的函数或方法具有相同名称的声明,参数列表和定义不同
- 重载决策
- 调用一个重载函数或重载运算符时,编译器需要比较调用函数时的参数类型与定义时的参数类型,来选择最合适的重载函数和重载运算符,这个过程称为重载决策
函数重载
-
规则
- 函数名相同
- 参数列表不同
- 与返回类型无关
-
示例
// 两个整数相加 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; }