Review cpp day07

回顾:
Review cpp day01
Review cpp day02
Review cpp day03
Review cpp day04
Review cpp day05
Review cpp day06

十九、成员指针//了解

1、成员变量指针

  • 1)定义:类型 类名::*指针变量名 = &类名::变量;
  • 2)使用
    • 对象.*成员指针变量名;
      注: ".*"称为成员指针解引用操作符
    • 对象指针->*成员指针变量名;
      注: "->*"称为间接成员指针解引用操作符

01menptr.cpp

#include <iostream>
using namespace std;

class Student{
public:
	Student(const string& name):m_name(name){}
	string m_name;
};
int main(void){
	string Student::*pname = &Student::m_name;
	Student s("张飞");
	Student* ps = new Student("赵云");
	cout << s.*pname << endl;//张飞
	cout << ps->*pname << endl;//赵云
	delete ps;
	return 0;
}

2、成员函数指针

  • 1)定义: 返回类型 (类名::*成员函数指针)(形参表) = &类名::成员函数名;
  • 2)使用
    • (对象.*成员函数指针)(实参表);
    • (对象指针->*成员函数指针)(实参表);

02menptr.cpp

#include <iostream>
using namespace std;

class Student{
public:
	Student(const string& name):m_name(name){}
	void who(void){
		cout << m_name << endl;
	}
	string m_name;
};
int main(void){
	void (Student::*pwho)(void) = &Student::who;
	Student s("张飞");
	Student* ps = new Student("赵云");
	(s.*pwho)();//张飞
	(ps->*pwho)();//赵云
	delete ps;
	return 0;
}

二十、操作符重载

eg:复数 x+yi, 实现(1+2i) + (3+4i) = 4 + 6i

1、双目操作符的重载 L#R

1.1、运算类的双目操作符:+ - …
  • 左右操作数既可以是左值也可以是右值
  • 表达式结构是右值
  • 两种实现方式:
    • 1)成员函数形式
      L#R的表达式可以被编译器翻译成L.operator#(R)这样成员函数调用形式,该函数的返回结果即使表达式的结果。
    • 2)全局函数形式
      L#R的表达式可以被编译器翻译成::operator#(L, R)这样全局函数调用形式,该函数的返回结果即使表达式的结果。
      注: 使用“friend”关键字,可以把一个全局函数声明为某个类的友元,友元函数可以访问类中任何成员。

03complex.cpp(第一种实现方式)

#include <iostream>
using namespace std;

class Complex{
public:
	Complex(int r, int i):m_r(r), m_i(i){}
	void print(void)const{
		cout << m_r << '+' << m_i << 'i' << endl;
	}
	//c1+c2==>c1.operator+(c2)
	/*
	*const关键字的意义:
	*1)修饰返回值,为了返回右值,即返回的对象只能是右值
	*2)常引用,为了支持常量型右操作数(右值),即传入的形参c即可以是普通引用,也可以是常引用
	*3)常函数,为了支持常量型左操作数(左值),即调用operator+的对象是常引用对象,也可以是普通对象
	*/
	const Complex operator+(const Complex& c)const{
		Complex res(m_r+c.m_r, m_i+c.m_i);
		return res;
	}
private:
	int m_r;//实部
	int m_i;//虚部
};
int main(void){
	Complex c1(1, 2);
	Complex c2(3, 4);
	c1.print();
	c2.print();
	c1.operator+(c2);
	Complex c3 = c1 + c2;
	c3.print();//4+6i
	return 0;
}

03complex.cpp(第二种实现方式)

#include <iostream>
using namespace std;

class Complex{
public:
	Complex(int r, int i):m_r(r), m_i(i){}
	void print(void)const{
		cout << m_r << '+' << m_i << 'i' << endl;
	}
	//c1+c2==>c1.operator+(c2)
	/*
	*const关键字的意义:
	*1)修饰返回值,为了返回右值
	*2)常引用,为了支持常量型右操作数(右值)
	*3)常函数,为了支持常量型左操作数(左值)
	*/
	const Complex operator+(const Complex& c)const{
		Complex res(m_r+c.m_r, m_i+c.m_i);
		return res;
	}
private:
	int m_r;//实部
	int m_i;//虚部
	
	//友元函数可以访问类中的私有成员
	friend const Complex operator-(const Complex& l, const Complex& r);
};

const Complex operator-(const Complex& l, const Complex& r){
	Complex res(l.m_r-r.m_r, l.m_i-r.m_i);
	return res;
}

int main(void){
	Complex c1(1, 2);
	Complex c2(3, 4);
	c1.print();
	c2.print();
	c1.operator+(c2);
	Complex c3 = c1 + c2;
	c3.print();//4+6i
	
	//::operator-(c2, c1)
	c3 = c2 - ci;
	c3.print();//2+2i
	return 0;
}
1.2、赋值类的双目操作符:+= -= …
  • 左操作数必须是左值,右操作数可以是左值也可以是右值
  • 表达式的结果是左值,就是左操作数的自身。
int a = 3, b= 5;
(a +=  b) = 10;//a+=b,a=10
(a +=  5) = 10;
  • 两种实现方式:
    • 1)成员函数形式
      L # R ==》L.operator#(R)
    • 2)全局函数形式
      L # R ==》::operator#(L, R)

04complex.cpp

#include <iostream>
using namespace std;

class Complex{
public:
	Complex(int r, int i):m_r(r), m_i(i){}
	void print(void)const{
		cout << m_r << '+' << m_i << 'i' << endl;
	}
	//+=:成员函数形式
	Comple& operator+=(const Complex& c){
		m_r += c.m_r;
		m_i += c.m_i;
		return *this;
	}

	//友元函数可以把定义直接写在类的内部,但是它不属于类,本质上还是全局函数
	friend Complex& operator-=(Complex& l, const Complex& r){
		l.m_r -= r.m_r;
		l.m_i -= r.m_i;
		return l;
	}
private:
	int m_r;//实部
	int m_i;//虚部
};

int main(void){
	Complex c1(1, 2);
	Complex c2(3, 4);
	c1 += c2;//c1.operator+=(c2)
	c1.print();//4+6i

	c1 -= c2;//::operator-=(c1, c2)
	c1.print();//1+2i
	return 0;
}

2、单目操作符重载#O

2.1、计算类的单目操作符:-(取负) ~…
  • 操作数可以是左值也可以是右值
  • 表达式结果是右值
  • 两种实现方式:
    • 1)成员函数形式:
      #O ==》O.operator#();
    • 2)全局函数形式
      #O ==》::operator#(O);

05Integer.cpp

#include <iostream>
using namespace std;
class Integer{
public:
	Integer(int i=0):m_i(i){}
	void print(void)const{
		cout << m_i << endl;
	}
	//-:成员函数形式
	const Integer operator-(void)const{
		Integer res(-m_i);
		return res;
	}
	//~:全局函数形式(自定义表示乘方)
	friend const Integer operator~(const Integer& i){
		Integer res(i.m_i * i.m_i);
		return res;
	}
private:
	int m_i;
};
int main(void){
	Integer i(100);
	Integer j = -i;//i.operator-();
	j.print();//100
	j = ~i;
	j.print();//10000
	return 0;
}
2.2、自增减单目操作符:前后++、--
  • 1)前++、--
    • 操作数必须是左值;
    • 表达式结果也是左值,就是操作数的自身。
    • 两种实现方式:
      • 成员函数 #O==》O.operator#()
      • 全局函数 #O==》::operator#(O)
int a = 1;
cout << ++a << endl;//2
cout << a << endl;//2
++a = 10;//ok
cout << a << endl;//10
++++++a;//ok
cout << a << endl;//13
  • 2)后++、--
    • 操作数必须是左值;
    • 表达式结果是右值,是操作数自增减前的副本。
    • 两种实现方式:
      • 成员函数 O#==》O.operator#(哑元)
      • 全局函数 O#==》::operator#(O,哑元)
        注: 哑元只是为了区分前、后 ++, --
int a = 1;
cout << a++ << endl;//1
cout << a << endl;//2

06Integer.cpp

#include <iostream>
using namespace std;
class Integer{
public:
	Integer(int i=0):m_i(i){}
	void print(void)const{
		cout << m_i << endl;
	}
	//前++:成员函数形式
	Integer& operator++(void){
		++m_i;
		return *this;
	}
	//前--:全局函数形式
	friend Integer& operator--(Integer& i){
		--i.m_i;
		return i;
	}
	//后++:成员函数形式
	const Integer operator++(int/*哑元*/){
		Integer old = *this;
		++*this;//++m_i;
		return old;
	}
	//后--:全局函数形式
	friend const Integer operator--(Integer& i, int/*哑元*/){
		Integer old = i;
		i--;
		return old;
	}
	
private:
	int m_i;
};
int main(void){
	Integer i(100);
	Integer j = ++i;//i.operator++()
	i.print();//
	j.print();//

	j = ++++++i;
	i.print();//104
	j.print();//104

	j = --i;//::operator--(i)
	i.print();//103
	j.print();//103
	
	j = ------i;
	i.print();//100
	j.print();//100
	
	j = i++;//i.operator++(0)
	i.print();//101
	j.print();//100
	
	j = i--;//::operator--(i, 0)
	i.print();//100
	j.print();//101

	return 0;
}
3、插入和提取操作符:<< >>
  • 功能:实现自定义类型的对象的直接输入和输出
    注: 只能用全局函数形式,因为ostream cout 与 istream cin是c++的标准库中的东西,难以改变源码,所以只能用全局函数形式::operator<<(cout/cin, a);

07io_operator.cpp

#include <iostream>
ostream cout;
istream cin;

//通用形式,只要将RIGHT& 替换为对应的类名就行
friend ostream& operator<<(ostream& os, const RIGHT& right){......}
friend istream& operator>>(istream& is, RIGHT& right){......}

cout << a << b << c;//cout<< a   cout << b << c;  cout << a   cout << b  cout << c;
cin >> a >> b >> c; 

03complex.cpp

#include <iostream>
using namespace std;

class Complex{
public:
	Complex(int r, int i):m_r(r), m_i(i){}
	friend ostream& operator<<(ostream& os, const Complex& c){
		os << c.m_r << "+" << c.m_i << "i";
		return os;
	}
	friend istream& operator>>(istream& is, Complex& c){
		is >> c.m_r >> c.m_i;
		return is;
	}
private:
	int m_r;//实部
	int m_i;//虚部

};

int main(void){
	Complex c1(1, 2);
	Complex c2(3, 4);
	//::operator << (cout, c1);
	cout << c1 << endl;
	cout << c1 << ',' << c2 << endl;
	Complex c3(0, 0);
	cout << "请输入一个复数的(实部和虚部):";
	cin >> c3;//::operator>>(cin, c3);
	cout << c3 << endl;
	return 0;
}
  • 练习:实现一个3*3矩阵,支持如下操作符重载:+ - += -(负) <<(输出)
class M33{
public:
	M33(void){
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++0){
				m_a[i][j] = 0;
			}
		}
	}
	M33(int a[][3]){
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++0){
				m_a[i][j] = a[i][j];
			}
		}
	}

private:
	int m_a[3][3];
};
int main(void){
	int a1[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	M33 m1(a1);
	int a2[3][3] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
	M33 m2(a2);
	return 0;
}

08M33.cpp

#include <iostream>
#include <iomanip>//setw(4)引用的头文件
using namespace std;

class M33{
public:
	M33(void){
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++0){
				m_a[i][j] = 0;
			}
		}
	}
	M33(int a[][3]){
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++0){
				m_a[i][j] = a[i][j];
			}
		}
	}
	friend ostream& operator<<(ostream& os, const M33& m){
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				//setw(4):设置显示的域宽
				os << setw(4) << m.m_a[i][j];
			}
			os << endl;
		}
		return os;
	}
	const M33 operator+(const M33& that)const{
		int res[3][3] = {0};
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				res[i][j] = m_a[i][j] + that.m_a[i][j];
			}
		}
		return M33 (res);//临时类对象的可以省略类名
	}
	
	const M33 operator-(const M33& that)const{
		int res[3][3] = {0};
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				res[i][j] = m_a[i][j] - that.m_a[i][j];
			}
		}
		return M33 (res);//临时类对象的可以省略类名
	}
	
	M33& operator+=(const M33& m){
		*this = *this + m;//函数复用,使用上面的operator+
		return *this
	}
	M33& operator-=(const M33& m){
		*this = *this - m;//函数复用,使用上面的operator-
		return *this
	}
	
	const M33 operator-(void)const{
		//M33(): 以无参形式创建临时对象
		return M33() - *this;
	}
private:
	int m_a[3][3];
};
int main(void){
	int a1[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	M33 m1(a1);
	int a2[3][3] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
	M33 m2(a2);

	cout << m1 << endl;
	cout << m2 << endl;

	cout << "m1+m2:" << endl;
	cout << m1+m2 << endl;
	cout << "m1-m2:" << endl;
	cout << m1-m2 << endl;

	cout << "m1+=m2:" << endl;
	cout << m1+=m2 << endl;
	cout << m1 << endl;
	cout << "m1-=m2:" << endl;
	cout << m1-=m2 << endl;
	cout << m1 << endl;

	return 0;
}
4、下标操作符重载:[]
  • 功能:让一个对象像数组一样去使用
    注: 非-常对象返回左值,常对象返回右值
string s = "hello";
//s.operator[](0)
s[0] = 'H'//ok

const string s2 = "hello";
//s2.operator[](0)
s2[0] = 'H';//error

09array_operator.cpp

#include <iostream>
using namespace std;

//定义表示容器的类,里面存放多个int
class Array{
public:
	Array(size_t size){
		m_data = new int[size];
	}
	~Array(void){
		delete[] m_data;
	}
	int& operator[](size_t i){
		return m_data[i];
	}
	const int& operator[](size_t i)const{
		return m_data[i];
	}
private:
	int *m_data;
};

int main(void){
	Array arr(10);
	arr[0] = 100;
	arr[1] = 200;
	cout << arr[0] << ',' << arr[1] << endl;

	const Array& rarr = arr;
	cout << rarr[0] << ',' << rarr[1] << end;
	//rarr[1] = 123;//error

	return 0;
}
5、函数操作符:()
  • 功能:让一个对象可以像函数一样使用
    注: 对参数个数、参数类型、返回值类型没有限制。
class A{...};
A a;
a(100, 200);//a.operator()(100,200)

10func_operator.cpp

#include <iostream>
using namespace std;

class Func{
public:
	double operator()(double d){
		return d*d;
	}
};
int main(void){
	Func func;
	//func.operator()(3.14)
	cout << func(3.14) << endl;

	return 0;
}
6、new/delete操作符
static void* operator new(size_t size){...}
static void operator delete(void* p){...}

11new_operator.cpp

#include <iostream>
#include <cstdlib>
using namespace std;

class A{
public:
	A(void){
		cout << "A::A()" << endl;
	}
	~A(void){
		cout << "A::~A()" << endl;
	}
	static void* operator new(size_t size){
		cout << "A::new" << endl;
		void* pv = malloc(size);
		return pv;
	}
	static void operator delete(void* pv){
		cout << "A::delete" << endl;
		free(pv);
	}
};
int main(void){
	//1) A* pa = (A*)A::operator new(sizeof(A))
	//2) pa->A::A()
	A* pa = new A;
	
	//1) pa->A::~A()
	//A::operator delete(pa);
	delete pa;
	
	return 0;
}
总结:操作符重载的限制
  • 1)不是所有的操作符都可以重载,下列操作符不能重载

    • 作用域限定符“::”
    • 直接成员访问操作符“.”
    • 直接成员指针解引用操作符“.*”
    • 条件操作符“?:”
    • 字节长度操作符“sizeof”
    • 类型信息操作符“typeid”(后面讲)
  • 2)如果一个操作符的所有操作数都是基本类型,则无法实现重载
    eg:int operator+(int a, int b){return a-b;}//error

  • 3)操作符重载不会改变编译器预定义的优先级

  • 4)操作符的重载不能改变操作数的个数

  • 5)无法通过操作符重载发明新的操作符
    eg:operator@(...){...}//error

扩展练习V5.0:实现企业员工管理系统

  • 需求:为员工类增加:<< == != 操作符支持
class Employee{
	ostream& operator<<(ostream& os, const Employee& emp){...}
	//根据员工的ID号和参数id比较是否相等
	bool operator==(int id){}
	bool operator!=(int id){}
};

Employee.h

#include <iostream>
#include <cstdio>
using namespace std;

class Employee{
public:
	Employee(const string& name, double salary);
	~Employee(void);
	void printInfo(void)const;
	void claSalary(void);
	void setId(int id);
	void setName(const string& name);
	void setSalary(double salary);
	void saveInfo(void)const;

	//根据员工对象的id和参数id比较,是否相等
	bool operator==(int id)const;
	bool operator!=(int id)const;

	friend ostream& operator<<(ostream& os, const Employee& emp);
private:
	//禁止拷贝构造函数和拷贝复制
	Employee& operator = (const Employee&);
	Employee(const Employee&);
private:
	int m_id;//工号
	string m_name;//姓名
	double m_salary;//工资
	FILE* file;
public:
	//获取员工人数
	static const int& getEmployeeCount(void);
private:
	static int m_count;//记录员工人数
};

Employee.cpp

#include "Employee.h"
Employee::Employee(const string& name, double salary)
		:m_name(name), m_saraly(salary){
	//读取ID
	FILE* fp = fopen("id.txt", "r+");
	fscanf(fp, "%d", &m_id);
	//将文件读写指针定位到文件头
	fseek(fp, 0, SEEL_SET);
	//ID+1, 再保存回id.txt
	fprintf(fp, "%d", m_id+1);
	//关闭id.txt
	fclose(fp);

	//将ID转换为字符串
	char filename[20] = {0};
	sprintf(filename, "%d", m_d);
	//根据id创建文件保存当前员工信息
	file = fopen(filename, "w");
	//保存员工信息
	saveInfo();
	
	//记录员工人数
	++m_count;
	//保存与纳贡人数
	FILE* fp2 = fopen("count.txt", "w");
	fprintf(fp2, "%d", m_count);
	fclose(fp2);
}
Employee::~Employee(void){
	fclose(file);
	file =NULL;
}
Employee::Employee(const Employee& that){
	char filename[20] = {0};
	sprintf(filename, "%d", that.m_id);
	file = fopen(filename, "r+");
	m_id = that.m_id;
	m_name = that.m_name;
	m_salary = that.m_salary;
}
void Employee::printInfo(void)const{
	cout << "姓名:" << m_name << endl;
	cout << "工号:" << m_id << endl;
	cout << "基础工资:" << m_salary << endl; 
}
void Eployee::calSalary(void){
	cout << "请输入出勤天数:";
	int days;
	cin >> days;
	double basic = m_salary * (days/23.0);
	double merit = basic / 2;
	cout << "总工资为:" << (basic + merit) << endl;
}
void Employee::setid(int){
	if(id < 10000){
		cout << "无效的工号" << endl;
	}
	else{
		m_id = id;
	}
}
void Employee::setName(const string& name){
	if(name.size() > 20){
		cout << "无效的姓名" << endl;
	}
	else{
		m_name = name;
	}
}
void Employee::setSalary(double){
	if(salary < 0){
		cout << "无效工资" << endl;
	}
	else{
		m_salary = salary;
	}
}
void Employee::saveInfo(void)const{
	fseek(file, 0, SEEK_SET);
	fprintf(file, "%d %s %g", m_id, m_name.c_str(), m_salary);
}
//静态成员需要在类的外部单独定义和初始化
int Employee::m_count = 0;

count int& Employee::getEmployeeCount(void){
7this	FILE* fp = fopen("count.txt", "r");
	//加载员工人数
	fscanf(fp, "%d", &m_count);
	fclose(fp);
	return m_count;
}
//根据员工对象的id和参数id比较,是否相等
bool Employee::operator==(int id)const{
	if(m_id ==id){
		return true;
	}
	else{
		return false;
	}
}
bool Employee::operator!=(int id)const{
	return !(*this == id);//函数复用
}
//全局函数
ostream& operator<<(ostream& os, const Employee& emp){
	os << "Employee(" << emp.m_id << "," << emp.m_name << em.m_salary << ")";
	return os;
}

main.cpp

#include "Employee.h"
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
void init(void){
	if(access("id.txt", F_OK) == -1){
		FILE* fp = fopen("id.txt", "w");//记录工号
		if(fp == NULL){
			perror("fopen"),exit(-1);
		}
		fprintf(fp, "%d", 10001);
		fclose(fp);
	}
	if(access("count.txt", F_OK) == -1){
		FILE* fp = fopen("count.txt", "w");//记录人数
		if(fp == NULL){
			perror("fopen"),exit(-1);
		}
		fprintf(fp, "%d", 0);
		fclose(fp);
	}
	else{
		//加载员工人数
		Employee::getEmployeeCount();
	}
}

int main(void){
	init();
	Employee emp("张三", 6600);
	//emp.printInfo();
	cout << emp << endl;
	emp.calSalary();

	if(emp == 10001){
		cout << "true" << endl;
	}
	else{
		cout << "false" << endl;
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值