运算符重载
运算符重载的基本方法:1.使用成员函数重载运算符 2.使用非成员函数(友元函数)重载运算符
一 使用成员函数重载运算符
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
/*
1斤牛肉 = 2斤猪肉
*/
// 猪类
class Pork
{
public:
Pork(int weight = 0)
{
this->weight = weight;
}
int getWeight() const { return weight; }
string description()
{
stringstream ret;
ret << "一头" << weight << "斤的猪";
return ret.str();
}
private:
int weight;
};
// 牛类
class Cow
{
public:
Cow(int weight = 0)
{
this->weight = weight;
}
// 使用成员函数重载运算符
Pork operator+(const Cow& cow);
Pork operator+(const Pork& pork);
private:
int weight;
};
// 使用成员函数重载运算符
Pork Cow::operator+(const Cow& cow)
{
int temp = (this->weight + cow.weight) * 2;
return Pork(temp);
}
// 使用成员函数重载运算符
Pork Cow::operator+(const Pork& pork)
{
int temp = this->weight * 2 + pork.getWeight();
return Pork(temp);
}
int main()
{
Cow c1(100);
Cow c2(200);
Pork p1 = c1 + c2; // (100+200)*2 = 600
cout << p1.description() << endl;
p1 = c1 + p1; // 100*2 + 600 = 800
cout << p1.description() << endl;
return 0;
}
二 使用非成员函数(友元函数)重载运算符
//-------------- Pork 类 -------------------
/* Pork.h */
#pragma once
#include <string>
using namespace std;
// 猪类
class Pork
{
public:
Pork(int weight = 0);
int getWeight() const;
string description();
private:
int weight;
};
/* Pork.cpp */
#include <sstream>
#include "Pork.h"
Pork::Pork(int weight)
{
this->weight = weight;
}
int Pork::getWeight() const
{
return weight;
}
string Pork::description()
{
stringstream ret;
ret << "一头" << weight << "斤的猪";
return ret.str();
}
//------------- Cow 类 ----------------
#pragma once
#include "Pork.h"
// 牛类
class Cow
{
public:
Cow(int weight = 0)
{
this->weight = weight;
}
// 使用非成员函数(友元函数)重载运算符
friend Pork operator+(const Cow& cow1, const Cow& cow2);
friend Pork operator+(const Cow& cow, const Pork& pork);
private:
int weight;
};
//-------------- main.cpp -----------------
#include <iostream>
#include <string>
#include <sstream>
#include "Pork.h"
#include "Cow.h"
using namespace std;
/*
1斤牛肉 = 2斤猪肉
*/
// 使用非成员函数(友元函数)重载运算符
Pork operator+(const Cow& cow1, const Cow& cow2)
{
int temp = (cow1.weight + cow2.weight) * 2;
return Pork(temp);
}
// 使用非成员函数(友元函数)重载运算符
Pork operator+(const Cow& cow, const Pork& pork)
{
int temp = cow.weight * 2 + pork.getWeight();
return Pork(temp);
}
int main()
{
Cow c1(100);
Cow c2(200);
Pork p1 = c1 + c2; // (100+200)*2 = 600
cout << p1.description() << endl;
p1 = c1 + p1; // 100*2 + 600 = 800
cout << p1.description() << endl;
return 0;
}
三 使用成员函数和非成员函数两种方法实现运算符重载的区别
-
区别:使用成员函数来实现运算符重载时,少写一个参数,因为第一个参数就是this指针
-
两种方式的选择:
- 1 一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)
- 2 一般情况下,双目运算符重载,使用友元函数实现更直观(方便实现 a+b 和 b+a 相同的效果,成员函数方式无法实现。)
例如: 100 + cow; 只能通过友元函数来实现 cow +100; 友元函数和成员函数都可以实现
-
特殊情况:
- 1 = () [ ] -> 不能重载为类的友元函数!!!(否则可能和 C++的其他规则矛盾), 只能使用成员函数形式进行重载。
- 2 如果运算符的第一个操作数要求使用隐式类型转换,则必须为友元函数(成员函数方式的第一个参数是 this 指针)
-
同一个运算符重载, 不能同时使用两种方式来重载,会导致编译器不知道选择哪一个(二义性)
四 运算符重载的禁区和规则
1.为了防止对标准类型进行运算符重载,C++规定重载运算符的操作对象至少有一个不是标准类型,而是用户自定义的类型,比如不能重载 1+2 但是可以重载 cow + 2 和 2 + cow // cow 是自定义的对象
2.不能改变原运算符的语法规则, 比如不能把双目运算符重载为单目运算
3.不能改变原运算符的优先级
4.不能创建新的运算符,比如 operator**就是非法的, operator*是可以的
5.不能对以下这四种运算符,使用友元函数进行重载 = 赋值运算符,()函数调用运算符,[ ]下标运算符,->通过指针访问类成员
6.不能对禁止重载的运算符进行重载
不能被重载的运算符:
可以被重载的运算符:
五 重载运算符+
class Man
{
public:
Man(string name = "未知", int age = 0, int score = 0);
Man operator+(const Man& other);
void print() const;
private:
string name;
int age;
int score;
};
Man::Man(string name, int age, int score)
{
this->name = name;
this->age = age;
this->score = score;
}
Man Man::operator+(const Man& other)
{
string name = this->name + other.name;
int age = this->age + other.age;
int score = this->score + other.score;
return Man(name, age, score);
}
void Man::print() const
{
cout << "name:" << this->name << " age:" << this->age << " score:" << this->score << endl;
}
int main()
{
Man t1("宫本", 13, 30);
Man t2("武藏", 15, 60);
cout << "t1: ";
t1.print();
cout << "t2: ";
t2.print();
Man t3 = t1 + t2;
cout << "t3: ";
t3.print();
return 0;
}
六 重载运算符= (注意返回类型和参数类型)
注意:
注意赋值运算符重载的返回类型和参数类型。
返回引用类型,便于连续赋值
参数使用引用类型,可以省去一次拷贝
参数使用 const, 便于保护实参不被破坏。
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
~Boy();
Boy& operator=(const Boy& boy); // 注意返回值类型和参数类型
string description();
private:
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
// 注意返回值类型和参数类型
Boy& Boy::operator=(const Boy& boy)
{
if (name)
{
delete name; // 释放原来的内存
}
this->name = new char[strlen(boy.name) + 1]; // 分配新的内存
strcpy_s(this->name, strlen(boy.name) + 1, boy.name);
this->age = boy.age;
this->salary = boy.salary;
//this->id = boy.id; // 根据需求决定要不要拷贝id
return *this; // 返回引用可以解决连续赋值的问题 例如 boy1 = boy2 = boy3;
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int main()
{
Boy boy1("小明", 18, 3000);
Boy boy2, boy3;
cout << boy1.description() << endl;
cout << boy2.description() << endl;
cout << boy3.description() << endl;
cout << endl << "boy3 = boy2 = boy1 执行后" << endl;
boy3 = boy2 = boy1;
cout << boy1.description() << endl;
cout << boy2.description() << endl;
cout << boy3.description() << endl;
return 0;
}
七 重载比较运算符 > < ==
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
~Boy();
Boy& operator=(const Boy& boy); // 注意返回值类型和参数类型
bool operator<(const Boy& boy);
bool operator>(const Boy& boy);
bool operator==(const Boy& boy);
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
// 注意返回值类型和参数类型
Boy& Boy::operator=(const Boy& boy)
{
if (name)
{
delete name;
}
this->name = new char[strlen(boy.name) + 1];
strcpy_s(this->name, strlen(boy.name) + 1, boy.name);
this->age = boy.age;
this->salary = boy.salary;
//this->id = boy.id; // 根据需求决定要不要拷贝id
return *this; // 返回引用可以解决连续赋值的问题 例如 boy1 = boy2 = boy3;
}
bool Boy::operator<(const Boy& boy)
{
if (this->power() < boy.power())
{
return true;
}
else
{
return false;
}
}
bool Boy::operator>(const Boy& boy)
{
if (this->power() > boy.power())
{
return true;
}
else
{
return false;
}
}
bool Boy::operator==(const Boy& boy)
{
if (this->power() == boy.power())
{
return true;
}
else
{
return false;
}
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
int main()
{
Boy boy1("小明", 18, 3000);
Boy boy2("小李", 23, 25000);
if (boy1 > boy2)
{
cout << "选择boy1" << endl;
}
else if (boy1 == boy2)
{
cout << "旗鼓相当" << endl;
}
else
{
cout << "选择boy2" << endl;
}
return 0;
}
八 重载运算符 []
#include <iostream>
#include <sstream>
#include <string>
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define ID_KEY "id"
#define POWER_KEY "power"
typedef enum
{
AGE,
SALARY,
ID,
POWER
}BOY_KEY_TYPE;
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
~Boy();
int operator[](const string index);
int operator[](BOY_KEY_TYPE index);
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
int Boy::operator[](const string index)
{
if (index == AGE_KEY)
{
return age;
}
else if (index == SALARY_KEY)
{
return salary;
}
else if (index == ID_KEY)
{
return id;
}
else if (index == POWER_KEY)
{
return power();
}
else
{
return -1;
}
}
int Boy::operator[](BOY_KEY_TYPE index)
{
if (index == AGE)
{
return age;
}
else if (index == SALARY)
{
return salary;
}
else if (index == ID)
{
return id;
}
else if (index == POWER)
{
return power();
}
else
{
return -1;
}
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
int main()
{
Boy boy1("小明", 18, 3000);
Boy boy2("小李", 23, 25000);
cout << "boy1 id:" << boy1[ID_KEY] << " age:" << boy1[AGE_KEY]
<< " salary:" << boy1[SALARY_KEY] << " power:" << boy1[POWER_KEY] << endl;
cout << "boy2 id:" << boy2[ID] << " age:" << boy2[AGE]
<< " salary:" << boy2[SALARY] << " power:" << boy2[POWER] << endl;
return 0;
}
九 重载运算符 << >>
因为用成员函数重载运算符<< >>使用起来不方便,所以用友元函数进行重载
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
~Boy();
//ostream& operator<<(ostream& os) const; //这种方式用起来很不方便,所以要用友元函数重载<<
friend ostream& operator<<(ostream& os, const Boy& boy);
friend istream& operator>>(istream& is, Boy& boy);
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
//ostream& Boy::operator<<(ostream& os) const
//{
// os << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
// return os;
//}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
ostream& operator<<(ostream& os, const Boy& boy)
{
os << "id:" << boy.id << " 姓名:" << boy.name << " 年龄:" << boy.age << " 薪资:" << boy.salary;
return os;
}
istream& operator>>(istream& is, Boy& boy)
{
string name;
is >> name >> boy.age >> boy.salary;
if (boy.name)
{
delete boy.name;
}
boy.name = new char[name.length() + 1];
strcpy_s(boy.name, name.length() + 1, name.c_str());
return is;
}
int main()
{
Boy boy("小明", 18, 3000);
// 用成员函数重载<<
//cout << boy1; // cout.operator<<(boy1)
//boy1 << cout; // 这种方式用起来很不方便,所以不用成员函数重载<<
cout << boy << endl;
cout << "请依次输入姓名,年龄,薪资:";
cin >> boy;
cout << boy << endl;
return 0;
}
十 重载类型运算符
10.1 普通类型 --> 类类型
需求:
Boy boy1 = 10000; // 薪资 构造函数Boy(int);
Boy boy2 = "Rock" // 姓名 构造函数 Boy(char *);
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
Boy(int salary);
Boy(const char* name);
~Boy();
friend ostream& operator<<(ostream& os, const Boy& boy);
friend istream& operator>>(istream& is, Boy& boy);
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::Boy(int salary)
{
const char* defaultName = "未命名";
this->name = new char[strlen(defaultName)+1];
strcpy_s(this->name, strlen(defaultName) + 1, defaultName);
this->age = 0;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::Boy(const char* name)
{
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = 0;
this->salary = 0;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
ostream& operator<<(ostream& os, const Boy& boy)
{
os << "id:" << boy.id << " 姓名:" << boy.name << " 年龄:" << boy.age << " 薪资:" << boy.salary;
return os;
}
istream& operator>>(istream& is, Boy& boy)
{
string name;
is >> name >> boy.age >> boy.salary;
if (boy.name)
{
delete boy.name;
}
boy.name = new char[name.length() + 1];
strcpy_s(boy.name, name.length() + 1, name.c_str());
return is;
}
int main()
{
/*
* 需求:
Boy boy1 = 10000; // 薪资 构造函数Boy(int);
Boy boy2 = "Rock" // 姓名 构造函数 Boy(char *);
*/
Boy boy1 = "小明";
Boy boy2 = 5000;
cout << boy1 << endl;
cout << boy2 << endl;
return 0;
}
10.2 类类型 --> 普通类型
调用特殊的运算符重载函数,类型转换函数,不需要写返回类型
类型转换函数:operator 普通类型 ()
需求:
Boy boy1(“小明”, 28, 10000);
int power = boy1; // power();
char *name = boy1; // “小明”
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
~Boy();
friend ostream& operator<<(ostream& os, const Boy& boy);
friend istream& operator>>(istream& is, Boy& boy);
// 特殊的运算符重载:类型转换函数,不需要写返回类型
operator int() const;
operator char* () const;
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
Boy::operator int() const
{
return power();
}
Boy::operator char* () const
{
return name;
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
ostream& operator<<(ostream& os, const Boy& boy)
{
os << "id:" << boy.id << " 姓名:" << boy.name << " 年龄:" << boy.age << " 薪资:" << boy.salary;
return os;
}
istream& operator>>(istream& is, Boy& boy)
{
string name;
is >> name >> boy.age >> boy.salary;
if (boy.name)
{
delete boy.name;
}
boy.name = new char[name.length() + 1];
strcpy_s(boy.name, name.length() + 1, name.c_str());
return is;
}
int main()
{
Boy boy1("小明", 20, 5000);
int power = boy1; //薪资 + (100 - 年龄)* 1000 5000+80*1000 = 85000
char* name = boy1;
cout << boy1 << endl;
cout << "power:" << power << endl;
cout << "name:" << name << endl;
return 0;
}
10.3 类类型A --> 类类型B
调用对应的只有一个参数【参数的类型就是类类型 A】的构造函数 也可以使用类型转换函数,但是使用对应的构造函数更合适。
实例: 把 Boy 类型,转换为 Man 类型
#include <iostream>
#include <sstream>
#include <string>
//------------------- Boy 类 ------------------------
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define ID_KEY "id"
#define POWER_KEY "power"
typedef enum
{
AGE,
SALARY,
ID,
POWER
}BOY_KEY_TYPE;
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
Boy(int salary);
Boy(const char* name);
~Boy();
Boy& operator=(const Boy& boy); // 注意返回值类型和参数类型
bool operator<(const Boy& boy);
bool operator>(const Boy& boy);
bool operator==(const Boy& boy);
int operator[](const string index) const;
int operator[](BOY_KEY_TYPE index) const;
//ostream& operator<<(ostream& os) const; //这种方式用起来很不方便,所以要用友元函数重载<<
friend ostream& operator<<(ostream& os, const Boy& boy);
friend istream& operator>>(istream& is, Boy& boy);
// 特殊的运算符重载:类型转换函数,不需要写返回类型
operator int() const;
operator char* () const;
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::Boy(int salary)
{
const char* defaultName = "未命名";
this->name = new char[strlen(defaultName)+1];
strcpy_s(this->name, strlen(defaultName) + 1, defaultName);
this->age = 0;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::Boy(const char* name)
{
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = 0;
this->salary = 0;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
// 注意返回值类型和参数类型
Boy& Boy::operator=(const Boy& boy)
{
if (name)
{
delete name;
}
this->name = new char[strlen(boy.name) + 1];
strcpy_s(this->name, strlen(boy.name) + 1, boy.name);
this->age = boy.age;
this->salary = boy.salary;
//this->id = boy.id; // 根据需求决定要不要拷贝id
return *this; // 返回引用可以解决连续赋值的问题 例如 boy1 = boy2 = boy3;
}
bool Boy::operator<(const Boy& boy)
{
if (this->power() < boy.power())
{
return true;
}
else
{
return false;
}
}
bool Boy::operator>(const Boy& boy)
{
if (this->power() > boy.power())
{
return true;
}
else
{
return false;
}
}
bool Boy::operator==(const Boy& boy)
{
if (this->power() == boy.power())
{
return true;
}
else
{
return false;
}
}
int Boy::operator[](const string index) const
{
if (index == AGE_KEY)
{
return age;
}
else if (index == SALARY_KEY)
{
return salary;
}
else if (index == ID_KEY)
{
return id;
}
else if (index == POWER_KEY)
{
return power();
}
else
{
return -1;
}
}
int Boy::operator[](BOY_KEY_TYPE index) const
{
if (index == AGE)
{
return age;
}
else if (index == SALARY)
{
return salary;
}
else if (index == ID)
{
return id;
}
else if (index == POWER)
{
return power();
}
else
{
return -1;
}
}
//ostream& Boy::operator<<(ostream& os) const
//{
// os << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
// return os;
//}
Boy::operator int() const
{
return power();
}
Boy::operator char* () const
{
return name;
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
ostream& operator<<(ostream& os, const Boy& boy)
{
os << "id:" << boy.id << " 姓名:" << boy.name << " 年龄:" << boy.age << " 薪资:" << boy.salary;
return os;
}
istream& operator>>(istream& is, Boy& boy)
{
string name;
is >> name >> boy.age >> boy.salary;
if (boy.name)
{
delete boy.name;
}
boy.name = new char[name.length() + 1];
strcpy_s(boy.name, name.length() + 1, name.c_str());
return is;
}
//------------------- Man 类 ------------------------
class Man
{
public:
Man(const char* name, int salary);
Man(const Boy& boy);
~Man();
friend ostream& operator<<(ostream& os, Man& man);
private:
char* name;
int salary;
};
Man::Man(const char* name, int salary)
{
if (!name)
{
name = "未命名";
}
int len = strlen(name) + 1;
this->name = new char[len];
strcpy_s(this->name, len, name);
this->salary = salary;
}
Man::Man(const Boy& boy)
{
int len = strlen((char*)boy) + 1; //(char*)boy 调用 operator char* () const;
this->name = new char[len];
strcpy_s(this->name, len, (char*)boy);
this->salary = boy[SALARY]; //boy[SALARY] 调用int Boy::operator[](BOY_KEY_TYPE index) const
}
Man::~Man()
{
if (name)
{
delete name;
}
}
ostream& operator<<(ostream& os, Man& man)
{
os << "name:" << man.name << " salary:" << man.salary;
return os;
}
//--------------------- main 函数 ----------------------------
int main()
{
Boy boy("小明", 20, 5000);
Man man = boy;
cout << boy << endl;
cout << man << endl;
return 0;
}
十一 常见错误总结
11.1 const导致的异常bug
#include <iostream>
#include <sstream>
#include <string>
//------------------- Boy 类 ------------------------
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define ID_KEY "id"
#define POWER_KEY "power"
typedef enum
{
AGE,
SALARY,
ID,
POWER
}BOY_KEY_TYPE;
using namespace std;
class Boy
{
public:
Boy();
Boy(const char* name, int age, int salary);
~Boy();
int operator[](const string index) const;
int operator[](int index);
string description();
private:
int power() const; // 综合能力值
char* name; // 姓名
int age; // 年龄
int salary; // 薪资
int id; // id
static int LAST_ID; // 最后一个id号
};
// 初始化静态数据成员
int Boy::LAST_ID = 0;
Boy::Boy()
{
name = new char('\0');
age = 0;
salary = 0;
id = ++LAST_ID;
}
Boy::Boy(const char* name, int age, int salary)
{
if (!name)
{
name = "未命名";
}
this->name = new char[strlen(name) + 1];
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->id = ++LAST_ID;
}
Boy::~Boy()
{
if (name)
{
delete name;
}
}
int Boy::operator[](const string index) const
{
if (index == AGE_KEY)
{
return age;
}
else if (index == SALARY_KEY)
{
return salary;
}
else if (index == ID_KEY)
{
return id;
}
else if (index == POWER_KEY)
{
return power();
}
else
{
return -1;
}
}
int Boy::operator[](int index)
{
if (index == AGE)
{
return age;
}
else if (index == SALARY)
{
return salary;
}
else if (index == ID)
{
return id;
}
else if (index == POWER)
{
return power();
}
else
{
return -1;
}
}
string Boy::description()
{
stringstream ret;
ret << "id:" << id << " 姓名:" << name << " 年龄:" << age << " 薪资:" << salary;
return ret.str();
}
int Boy::power() const
{
// 薪资 + (100 - 年龄)* 1000
int temp = salary + (100 - age) * 1000;
return temp;
}
//--------------------- main 函数 ----------------------------
int main()
{
const Boy boy("小明", 20, 5000);
//cout << boy[0] << endl; // 报错 const 对象只能调用const方法,所以这里不能调用 int operator[](int index);
return 0;
}
我们这里boy定义的是const对象,只能调用对应的const方法,所以这里报错
所以:
类的成员函数,如果已经确定不会修改任何数据成员,那么,最好把这个成员函数定义为const函数(int Boy::operator[](int index) const;
)
11.2 重载赋值运算符 operator= 的参数问题
-
赋值运算符的重载,应该使用这种方式:
Boy& operator=(const Boy &boy);
就是:参数要使用引用! -
如果定义成:
Boy& operator=(const Boy *boy);
将会没有效果,编译器不会识别为赋值运算符的重载
比如:boy2 = boy1 时不会调用这个函数 -
如果定义:
Boy& operator=(const Boy boy);
有效果,但是在调用时,会执行参数的传递
比如:boy2 = boy1;
就会执行: boy2.operator=(boy1);
就会执行: const Boy boy = boy1;
就会执行: Boy 类的拷贝构造函数- 执行Boy 类的拷贝构造函数 有两个影响:
1) 浪费性能
2) 如果没有自定义的拷贝构造函数,而且这个类又有指针成员时,就会调用自动生成的拷贝构造函数,导致浅拷贝,如果析构函数中,对这个指针指向的内存做了释放,那就导致数据损坏或崩溃!
- 执行Boy 类的拷贝构造函数 有两个影响:
-
小结:
1)赋值运算符的重载,一定要使用引用参数
2)如果一个类有指针成员,而且使用了动态内存分配,那么一定要定义自己的拷贝构造函数【要使用深拷贝】,避免调用自动生成的拷贝构造函数 因为自动生成的拷贝构造函数,是浅拷贝!