Review cpp day08

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

二十一、继承(Inheritance)

1、继承的概念

  • 通过一种机制表达类型之间共性和特性的方式,利用已有的数据类型定义新的数据类型,这种机制就是继承。
    eg:
人类:姓名、年龄、吃饭、睡觉
学生类:姓名、年龄、吃饭、睡觉、学号、学习
教师类:姓名、年龄、吃饭、睡觉、工资、授课
---------------------------------------------------
人类:姓名、年龄、吃饭、睡觉
学生类继承人类:学号、学习
教师类继承人类:工资、授课
	           人类(基类、父类)
	            /         \
           学生类	      教师类(派生类、子类)

注: 基类派生子类,子类继承基类

2、继承语法

class 子类:继承方式 基类,......{
	.......
};
  • 继承方式:
    • public:公有继承
    • protected:保护继承
    • private:私有继承

eg:

class Humen{姓名、年龄、吃饭、睡觉};
class Student:public Human{
	//学生类继承了人类
	//人类中的成员在当前学上类就可以直接使用
};

01inhert.cpp

#include <iostream>
using namespace std;

//人类
class Human{
public:
	Human(string name, int age):m_name(name), m_age(age){}
	void eat(const string& food){
		cout << "我在吃" << endl;
	}
	void sleep(int time){
		cout << "我睡了" << time << "小时" << endl;
	}
protected://保护成员可以在子类中被访问
	string m_name;
	int m_age;
};
//学生类(人类的一个子类)
class Student : public Human{
public:
	//Human(...)是从基类继承过来的成员初始化方式
	Student(const string& name, int age, int no) : Human(name, age), m_no(no){}
	void learn(const string& course){
		cout << "我在学" << coursr << endl;
	}
	void who(void){
		cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << endl;
	}
private:
	int m_no;
};
//教师类(人类的另一个子类)
class Teacher : public Human{
public:
	Teacher(const string& name, int age, double salary) : Human(name, age), m_salary(salary){}
	void teach(const string& course){
		cout << "我在讲" << course << endl;
	}
	void who(void){
		cout << "我叫" << m_name << ",今年" << m_age << "岁,工资是" << m_salary << endl;
	}
private:
	double m_salary;
};

int main(void){
	Student s("关羽", 35, 10011);
	s.who();
	s.eat("牛肉面");
	s.sleep(8);
	s.learn("孙子兵法");

	Teacher t("孙悟空", 30, 50000);
	t.who();
	t.eat("桃子");
	t.sleep(6);
	t.teach("春秋刀法");

	return 0;
}

3、公有继承的特性(public)******

  • 1)子类对象会继承基类属性的行为,通过子类对象可以访问基类中的成员,如同是基类对象在访问它们一样;
    注: 子类对象中包含基类的部分称为“基类子对象”
  • 2)向上造型:将子类类型的指针或引用转换成基类类型的指针或引用
    注: 这种操作性缩小的类型的转换,在编译器看来是安全的可以直接隐式完成转换。
	  基类
  	   ⬆
	  子类

eg:

	class Base{...};//基类
	class Derived : public Base{...};//子类

	void func1(Base& ){}
	void func2(Base* ){}
	
	int main(){
		Derived d;
		func1(d);//向上造型
		func2(&d);//向上造型
	}
  • 3)向下造型:将基类类型的指针或引用转换为子类类型的指着或引用;
	  基类
	   ⬇
	  子类

注: 这种操作性扩大的类型的转换,在编译器看来是危险的不可以直接隐式完成转换,但可以显示转换。

  • 4)子类继承基类的成员
    • 在类中,可以直接访问基类中的公有或保护成员,如同它们是子类自己的成员一样;
    • 基类中的私有成员子类也可以继承过来,但是会受到访问控制属性的限制,无法直接访问,如果子类需要访问基类中的私有成员,可以通过基类提供的公有或保护的接口函数来访问。
    • 基类的构造函数和析构函数,子类是无法继承的,但是可以在子类的构造函数使用初始化表显式指明基类部分的初始化方式。

01inhert.cpp

#include <iostream>
using namespace std;

//人类
class Human{
public:
	Human(string name, int age):m_name(name), m_age(age), m_id(123456){}
	void eat(const string& food){
		cout << "我在吃" << endl;
	}
	void sleep(int time){
		cout << "我睡了" << time << "小时" << endl;
	}
protected://保护成员可以在子类中被访问
	string m_name;
	int m_age;
	//私有成员子类无法直接访问,但是可以提供保护的接口函数来间接访问
	const int& getId(void){
		return m_id;
	}
private:
	int m_id;
};
//学生类(人类的一个子类)
class Student : public Human{
public:
	//Human(...)从基类中继承过来的成员初始化方式
	Student(const string& name, int age, int no) : Human(name, age), m_no(no){}
	void learn(const string& course){
		cout << "我在学" << coursr << endl;
	}
	void who(void){
		cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << endl;
		cout << "身份证号:" << getId() << endl;//间接访问基类私有成员
	}
private:
	int m_no;
};
//教师类(人类的另一个子类)
class Teacher : public Human{
public:
	Teacher(const string& name, int age, double salary) : Human(name, age), m_salary(salary){}
	void teach(const string& course){
		cout << "我在讲" << course << endl;
	}
	void who(void){
		cout << "我叫" << m_name << ",今年" << m_age << "岁,工资是" << m_salary << endl;
	}
private:
	double m_salary;
};

int main(void){
	Student s("关羽", 35, 10011);
	s.who();
	s.eat("牛肉面");
	s.sleep(8);
	s.learn("孙子兵法");

	Teacher t("孙悟空", 30, 50000);
	t.who();
	t.eat("桃子");
	t.sleep(6);
	t.teach("春秋刀法");

	//Student*-->Human*:向上造型
	Human* ph = &s;
	ph->eat("苹果");
	ph->sleep(6);
	//ph->learn("编程")//error

	//Human*->Student*:向下造型(安全的)
	//不能隐式转换,但可以显示转换
	Student* ps = static_cast<student*>(ph);
	ps->who();

	Human h("林黛玉", 20);
	//Human*->student*:向下造型(危险的)
	Student* ps2 = static_cast<Student*>(&h);
	ps2->who();

	return 0;
}
  • 5)子类隐藏基类的成员
    • 子类和基类中有同名的成员函数,因为作用域不同,不会有重载关系,而是一种隐藏关系。如果需要访问基类中隐藏的成员函数,可以通过“基类::”显式指明。
    • 如果隐藏的成员函数满足同名不同参重载条件,也可以通过using声明的方式,将基类的成员函数引入到子类的作用域,让它们形成重载关系,通过重载匹配来解决(//不推荐这种方式)

02inhert.cpp

class Base{
public:
	void foo(void){
		cout << "Base::foo" << endl;
	}
};
class Derived: public Base{
public:
	void foo(int i){
		cout << "Derived::foo" << endl;
	}
	//将基类foo函数引入当前子类作用域
	//using Base::foo;
};
int main(void){
	Derived d;
	d.Base::foo();
	d.foo(10);
	return 0;
}

4、继承方式和访问控制属性

  • 1)访问控制限定符:影响访问该成员的位置
访问控制限定符访问控制属性内部访问子类访问外部访问友元访问
public公有成员okokokok
protected保护成员okoknook
private私有成员oknonook
  • 2)基类继承方式:影响通过子类访问基类中的成员的可访问性
基类中的在公有子类中变成在保护子类中变成在私有子类中变成
公有成员公有成员保护成员私有成员
保护成员保护成员保护成员私有成员
私有成员私有成员私有成员私有成员

注: 向上造型的语法在保护继承或私有继承中不再使用

03inhert.cpp

#include <iostream>
using namespace std;

class A{
public:
	int m_public;
protected:
	int m_protected;
private:
	int m_private;
};
class B:public A{};
class C:protected A{};
class D:private A{};

class X:public B{
public:
	void func(void){
		m_public =10;
		m_pretected = 10;
		//m_private = 10;//error
	}
};
class Y:public C{
public:
	void func(void){
		m_public = 10;
		m_protected = 10;
		//m_private = 10;
	}
};
class Z:public D{
public:
	void func(void){
		//m_public = 10;
		//m_protected = 10;
		//m_private = 10;
	}
};
int main(void){
	B b;
	b.m_public = 10;
	//b.m_protected =10;//error
	//b.m_private = 10;//error

	C c;
	//c.m_public = 10;//error
	//c.m_protected = 10;//error
	//c.m_private = 10;error

	D d;
	//d.m_public =10;//error
	//d.m_protected = 10;error
	//d.m_private = 10;//error
	return 0; 
}

5、子类构造函数

  • 1)如果子类构造函数没有指明基类部分(基类子对象)的初始化方式,那么编译器将会调用基类的无参构造函数来初始化;
  • 2)如果希望基类子对象以有参的方式被初始化,需要在子类构造函数的初始化表中指明其初始化方式:
    class 子类:public 基类{
    	//基类(...):指明基类子对象的初始化方式
    	子类(...):基类(...){}
    };
    
  • 3)子类对象的构造过程
    • 分配内存
    • 构造基类子对象(按继承表顺序)
    • 构造成员子对象(按声明的顺序)
    • 执行子类的构造函数代码

04inhert.cpp

#include <iostream>
using namespace std;

class Base{
public:
	Base(void):m_i(0){
		cout << "Base::Base(void)" << endl;
	}
	Base(int i):m_i(i){
		cout << "Base::Base(int)" << endl;
	}
	int m_i;
};	
class Derived:public Base{
public:
	Derived(void){
		cout << "Derived::Derived(void)" << endl;
	}
	//Base(i):指明基类子类像初始化方式
	Derived(int i):Base(i){
		cout << "Derived::Derived(int)" << endl;
	}
};

int main(void){
	Derived d1;
	cout << d1.m_i << endl;//0
	Derived d2(123);
	cout << d2.m_i << endl;//123

	return 0;
}

6、子类的析构函数

  • 1)子类的析构函数,无论是自己定义的还是编译器缺省提供的,都会自动调用基类的析构函数, 析构基类子对象;
  • 2)子类对象的析构过程
    • 执行子类析构函数代码
    • 析构成员子对象(按声明的逆序)
    • 析构基类子对象(按继承表的逆序)
    • 释放内存

05inhert.cpp

#include <iostream>
using namespace std;
class Member{
public:
	Member(void):m_(0){
		cout << "Member::Member(void)" << endl;	
	}
	Member(int i):m_i(i){
		cout << "Member::Member(int)" << endl;
	}
	~Member(void){
		cout << "Member::~Member()" << endl;
	}
	int m_i;
};
class Base{
public:
	Base(void):m_i(0){
		cout << "Base::Base(void)" << endl;
	}
	Base(int i):m_i(i){
		cout << "Base::Base(int)" << endl;
	}
	~Base(void){
		cout << "Base::~Base()" << endl;
	}
	int m_i;
};	
class Derived:public Base{
public:
	Derived(void){
		cout << "Derived::Derived(void)" << endl;
	}
	//Base(i):指明基类子类像初始化方式
	//m_m(i):指明成员子对象初始化方式
	Derived(int i):Base(i), m_m(i){
		cout << "Derived::Derived(int)" << endl;
	}
	~Derived(void){
		cout << "Derived::~Derived(void)" << endl;
	}
	Member m_m;//成员子对象
};

int main(void){
	Derived d1;
	cout << d1.m_i << "," << d1.m_m << endl;//0,0
	/*Derived d2(123);
	cout << d2.m_i << "," << d2.m_m << endl;//123,123*/
	
	return 0;
}
Base::Base(void)
Member::Member(void)
Derived::Derived(void)
0,0
Derived::~Derived()
Member::~Member()
Base::~Base()
  • 3)基类的析构函数不会自动调用子类的析构函数。如果一个指向针子对象的基类指针使用delete操作符,实际被执行的仅是基类的析构函数,子类的析构函数执行不到,有内存泄漏的风险。
    class A{.....};
    class B:public A{......};
    A* pa = new B;//pa:指向子类对象的基类指针
    delete pa;//内存泄漏
    

07inherit.cpp

#include<iostream>
using namespace std;

class Base{
public:
	Base(void){
		cout << "基类动态资源的分配" << endl;
	}
	~Base(void){
		cout << "基类动态资源的释放" << endl;
	}
};

class Derived::public Base{
public:
	Derived(void){
		cout << "子类动态资源的分配" << endl;
	}
	~Derived(void){
		cout << "子类动态资源的释放" << endl;
	}
};
int main(void){
	//pb称为指向子类对象的基类指针
	Base* pb = new Derived;
	//......
	//只调用基类的析构函数,有内存泄漏风险
	delete pb;
	return 0;
}
基类动态资源的分配
子类动态资源的分配
基类动态资源的释放

7、子类的拷贝构造和拷贝赋值

  • 1)拷贝构造函数
    • 子类没有定义拷贝构造函数,编译器会为子类提供缺省的拷贝构造函数,该函数会自动调用基类的拷贝构造函数,以拷贝的方式来初始化基类子对象;
    • 子类定义了拷贝构造函数,那么需要使用初始化表,显示指明基类子对象也要以拷贝方式来初始化。
    class Base{};
    class Derived: public Base{
    	//Base(that):指明基类子对象以拷贝方式来初始化
    	Derived(const Derived& that):Base(that),...{}
    };
    
  • 2)拷贝复制操作符函数
    • 子类没有定义拷贝赋值函数,编译器会为子类提供缺省的拷贝赋值函数,该函数会自动调用基类的拷贝赋值函数,完成对基类子对象的复制;
    • 子类定义了拷贝赋值函数,需要显式调用基类的拷贝赋值函数,完成对基类子对象的复制。
    class Base{};
    class Derived: public Base{
    	............
    	//显式调用基类的拷贝赋值函数
    	Base::operator=(that)
    };
    

01inherit.cpp

#include <iostream>
using namespace std;

class Base{
public:
	Base(void):m_i(0);
	Base(int i):m_i(i){}
	Base(const Base& that):m_i(that.m_i){
		cout << "Base的拷贝构造" << endl;
	}
	Base& operator=(const Base& that){
		cout << "Base的拷贝赋值函数" << endl;
		if(&that != this){
			m_i = that.m_i;
		}
		return *this;
	}
	int m_i;
};
class Derived:public Base{
public:
	Derived(void):m_i(0){}
	Derived(int i1, int i2):Base(i1), m_i(i2){}

	//Base(that):指明基类子对象以拷贝方式来初始化
	Derived(const Derived& that):m_i(that.m_i), Base(that){}
	Derived& operator=(const Derived& that){
		if(&that != this){
			m_i = that.m_i;
			//Base.m_i = that.Base::m_i;
			
			//调用基类的拷贝赋值,赋值基类子对象
			Base::operator = (that);
		}
		return *this;
	}
	int m_i;
};
int main(void){
	Derived d1(100, 200);
	Derived d2(d1);
	cout << d1.Base.m_i << "," << d1.m_i << endl;
	cout << d2.Base.m_i << "," << d2.m_i << endl;

	Derived d3;
	d3 = d1;//d3.operator=(d1)
	cout << d3.Base::m_i << "," < d3.m_i << endl;
	return 0;
}
Base的拷贝构造
100,200
100,200
Base的拷贝赋值函
100,200

8、多重继承

  • 1)概念:一个子类同时继承多个基类,这样的继承结构称为多重继承。
  • 2)多重继承在向上造型的转换时,编译器会根据各个基类子对象的内存布局,进行适当的偏移计算,保证指针的类型与其所指向的目标对象类型一致。

02mul_inerit.cpp

#include <iostream>
using namespace std;

class Phone{//电话类
publicPhone(const string& number):m_number(number){}
	void call(const string& number){
		cout << m_number << "打给" << number << endl;
	}
private:
	string m_number;
};
class Player{//播放器类
public:
	Player(const string& media):m_media(media){}
	void play(const string& music){
		cout << m_media << "播放器播放" << music << endl;
	}
private:
	string m_media;
};
class Computer{//计算机类
public:
	Computer(const string& os):m_os(os){}
	void run(const string& app){
		cout << "在"  << m_os << "系统上运行" << app << endl;
	}
private:
	string m_os;
	
};
class SmartPhone:public Phone, public Player, public Computer{//智能手机类
public:
	SmartPhone(const string& number, const string& media, const string& os)
			:Phone(number), Player(media), Computer(os){}
};
int main(void){
	SmartPhone iphoneX("1886668888", "MP4", "Android");
	iphoneX.call("010-110");
	iphoneX.play("最炫小苹果.mp3");
	iphoneX.run("绝地求生");

	SmartPhone* p1 = &iphoneX;
	Phone* p2 = p1;
	Player* p3 = p1;
	Computer* p4 = p1;

	cout << "p1=" << p1 << endl;
	cout << "p2=" << p2 << endl;
	cout << "p3=" << p3 << endl;
	cout << "p4=" << p4 << endl;
	return 0;
}

在这里插入图片描述

  • 3)名字冲突问题
    • 一个子类的多个基类如果存在相同的成员,当通过子类访问这些成员时,编译器会报歧义错误–名字冲突。
    • 解决名字冲突问题的一般方法就是显式地使用作用域限定操作符,指明所访问的成员属于哪一个基类;
    • 如果产生冲突的成员是成员函数并且满足不同参数的条件,则还可以用using声明,让它们在子类中形成重载关系,通过重载解析来解决。

eg:

class Base1{
public:
	int m_i;
};
class Base2{
public:
	int m_i;
};
class Derived:public Base1, public Base2{
	//子类访问m_i//error
};

03mul_inherit.cpp

#include <iostream>
using namespace std;

class A{
public:
	void foo(void){
		cout << "A::foo(void)" << endl;
	}
};
class B{
public:
	void foo(int i){
		cout << "B::foo(int)" << endl;
	}
};
class C:public A, public B{
public:
	//using A::foo;
	//using B::foo;
};
int main(void){
	C c;
	//c.foo();error,名字冲突
	//c.foo(10);error,名字冲突
	c.A::foo();
	c.B::foo(100);
	return 0;
}

9、钻石继承

  • 1)一个子类的多个基类源自共同的基类祖先,这样的继承结构称为钻石继承。
	           A		         人类
              /   \		        /     \
             B    C	       学生类      教师类
              \   /	            \      /
                D		          班长
  • 2)公共基类(A)子对象在汇聚子类(D)对象中,存在对各实例,在汇聚子类中或者通过汇聚子类对象,去访问公共基类的成员,会因为继承路径不同而导致不一致。
  • 3)通过虚继承可以让公共基类(A)子对象在汇聚子类(D)对象中实例唯一,并为所有中间(B、C)对象共享,这样即使通过不同的继承路径所访问到公共基类的成员一定是一致的。
	 		A(int m_data)
              /    \
             B    	C(virtual public data)
              \    /
                D(负责构造A类子对象)

10、虚继承语法

  • 1)继承表中使用virtual关键字;
  • 2)位于继承链最末端(D)子类负责构造公共基类(A)子对象。
    在这里插入图片描述

04diamond.cpp

#include <iostream>
using namespace std;

class A{
public:
	A(int data):m_data(data){
		cout << "公共基类A:" << this << ",size=" << sizeof(A) << endl;
	}
protected:
	int m_data;
};
class B:virtual public A{//虚继承
public:
	B(int data):A(data){
		cout << "中间类B:" << this << ",size=" << sizeof(B) << endl;
	}
	void set(int data){
		m_data = data;
	}
};
class C:virtual public A{//虚继承
public:
	C(int data):A(data){
		cout << "中间类C:" << this << ",size=" << sizeof(C) << endl;
	}
	void get(void){
		return m_data;
	}
};
class D:public B, public C{
public:
	//虚继承时,D类构造函数负责构造A基类子对象
	D(int data):B(data), C(data), A(data){
			cout << "汇聚子类D:" << this << ",size=" << sizeof(D) << endl;
	}
};
int main(void){
	D d(100);
	cout << d.get() << endl;//100
	d.set(200);
	cout << d.get() << endl;//200
	return 0;
}

在这里插入图片描述
在这里插入图片描述

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

  • 需求:增加技术员类、经理类
    • 1)技术员:研发津贴(元/小时)
      • 基本工资 = 和普通员工一样
      • 绩效工资 = 工作小时数 * 研发津贴 * 进度因数(输入)
    • 2)经理:绩效奖金(元/月)
      • 基本工资 = 和普通员工一样
      • 绩效工资 = 绩效奖金 * 绩效因数(输入)
		      员工(Employee)
		     /    \
          技术员   经理
  • 提示:
	void printInfo(){
		printBasic();//打印公有信息
		printExtra();//打印特有信息
	}
	void calSalary(){
		//总工资 = 基本工资 + 绩效工资
		calBasic() + calMerit();
	}

Employee.h

#ifndef __EMPLOYEE_H__
#define __EMPLOYEE_H__


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

class Employee{
public:
	Employee(const string& name, double salary);
	~Employee(void);
	void printInfo(void)const;
protected:
	void printInfo(void)const;//公有信息
	void printExtra(void)const;//特有信息
public:
	//计算工资
	void claSalary(void);
protected:
	double calBasic(void);//基本工资
	double calMerit(void);//绩效工资
public:
	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;//保存员工信息指针
	double m_attend;//出勤率
public:
	//获取员工人数
	static const int& getEmployeeCount(void);
private:
	static int m_count;//记录员工人数
};

#endif //__EMPLOYEE_H__

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{
	printBasic();
	printExtra();
}
void Employee::printBase(void)const{
	cout << "姓名:" << m_name << endl;
	cout << "工号:" << m_id << endl;
	cout << "基础工资:" << m_salary << endl; 
}
void Employee::printExtra(void)const{
	cout << "职位:普通员工" << endl;
}
void Eployee::calSalary(void){
	double salary = calBasic() + calMerir();
	cout << "总工资为:" << salary << endl;
}
double Employee::calBasic(void){
	cout << "请输入出勤天数:";
	int days;
	cin >> days;
	m_attent = days/23.0;//计算出勤率
	return m_salary * m_attend;
	
}
double Employee::calMerit(void){
	return m_salary * m_attend / 2;
}
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;
}

Technician.h

#ifndef __TECHNICIAN_H__
#define __TECHNICIAN_H__

#include "Employee.h"

class Technician: public Employee{
public:
	Technician(const string& name,double salary, double allow);
	void printInfo(void)const;
	void printExtra(void)const;
	void calSalary(void);
	double calMerit(void);
	friend ostream& operator<<(ostream& os, const Technician& tech);
private:
	double m_allow;//研发津贴
};

#endif //__TECHNICIAN_H__

Technician.cpp

#include <Technician.h>

Technician::Technician(const string& name, double salary, double allow):
		Employee(name, salary), m_allow(allow){
	fprintf(file, "%g", m_allow);
}
void Technician::printInfo(void)const{
	printBasic();
	printExtra();
}
void Technician::printExtra(void)const{
	cout << "职位:技术员" << endl;
	cout << "研发津贴:" << m_allow << endl;
}
void Technician::calSalary(void){
	double salary = calBasic() + calMerit();
	cout << "总工资为:" << salary << endl;
}
void Technician::calMerit(void)const{
	cout << "请输入进度因数:";
	double factor;
	cin >> factor;
	return 23 * 8 * m_attend * m_allow * factor;
}
ostream& operator<<(ostream& os, const Technician& tech){
	os << "Technician(" << tech.name << "," << tech.m_id << ")";
}

Manager.h

#ifndef __MANAGER_H__
#define __MANAGER_H__

#include "Employee.h"

class Manager: public Employee{
public: 
	Manager(const string& name, double salary, double m_bonus);
	void printInfo(void)const;
	void printExtra(void)const;
	void calSalary(void);
	double calMerit(void);
private:
	double m_bonus;//绩效奖金
};

#endif //__MANAGER_H__

Manager.cpp

#include "Manager.h"

Manager::Manager(const string& name, double salary, double bonus):
		Employee(name, salary), m_bonus(bonus){
	//保存经理的绩效工资
	fprintf(file, "%g", m_bonus);	
}
void Manager::printfInfo(void)const{
	printBasic();
	printExtra();
}
void Manager::printExtra(void)const{
	cout << "职位:经理" << endl;
	cout << "绩效工资:" << m_bonus << endl;
}
void Manager::calSalary(void){
	double salary = calBasic() + calEerit();
	cout << "总工资为:" << salary << endl;
}
void Manager::calEerit(void){
	cout << "请输入j绩效因数:";
	double factor;
	cin >> factor;
	return m_bonus * factor;
}

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();
	cout << "======================" << endl;
	
	Technician tech("孔明", 8800, 30);
	//tech.printInfo();
	cout << tech << endl;
	tech.calSalary();
	cout << "======================" << endl;

	Manager manager("刘备", 12000, 5000);
	manager.printInfo();
	manager.calSalary();
	cout << "======================" << endl;
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值