C++中的代码重用(2)

C++中的代码重用(2),第1张

//class.h

#pragma once

#ifndef _CLASS_H_
#define _CLASS_H_

#include
using namespace std;

class Worker //抽象基类(包含纯虚函数的类)
{
private:
	string fullname;
	long id;
protected:
	virtual void Data() const;
	virtual void Get();
public:
	Worker() :fullname("no one"), id(0L) { };
	Worker(const string& s, long n) :fullname(s), id(n) { };
	//纯虚函数
	virtual ~Worker() = 0;
	virtual void Set() = 0;
	virtual void Show()const = 0;
};

//虚基类(用于MI多重继承)
class Waiter :virtual public Worker
{
private:
	int panache;
protected:
	void Data()const;
	void Get();
public:
	Waiter() :Worker(), panache(0){ };
	Waiter(const string& s, long n, int p = 0) : Worker(s, n), panache(p) { }; //默认参数从右往左开始设置
	Waiter(const Worker& wk, int p = 0) :Worker(wk), panache(p) { };
	void Set();
	void Show()const;
};

class Singer :virtual public Worker
{
protected:
	//创建类常量
	enum {other, alto, contralto, soprano, bass, baritone, tenor };
	enum {Vtypes = 7};
	void Data()const;
	void Get();
private:
	static const char* pv[Vtypes]; //静态变量,如果没有在定义的时候就初始化,则需要在实现文件中标明所属类中再进行初始化
	int voice;
public:
	Singer() :Worker(), voice(other) { };
	Singer(const string& s, long n, int v = other) :Worker(s, n), voice(v) { };
	Singer(const Worker& wk, int v = other) :Worker(wk), voice(v) { };
	void Set();
	void Show()const;
};

class SingingWaiter :public Singer, public Waiter
{
protected:
	void Data()const;
	void Get();
public:
	SingingWaiter() { };
	//MI的继承类需要显示的调用基类的构造函数,否则将自动调用基类的默认构造函数
	SingingWaiter(const string& s, long n, int p = 0, int v = other) :Worker(s, n), Waiter(s, n, p), Singer(s, n, v) { };
	SingingWaiter(const Worker& wk, int p = 0, int v = other) :Worker(wk), Waiter(wk, p), Singer(wk, v) { };
	//参数类型为基类对象引用和指针时,传递的参数可以是其继承类对象的引用和指针
	SingingWaiter(const Waiter& wk, int v = other) :Worker(wk), Waiter(wk), Singer(wk, v) { };  //此中的Waiter构造函数本应该接受两个参数,但其1第二个参数是一个默认参数,可以不传递参数.
	SingingWaiter(const Singer& wk, int p = 0) :Worker(wk), Waiter(wk, p), Singer(wk) { };
	void Set();
	void Show()const;
};





#endif

//fuc.cpp

#include"class.h"
#include


//Worker:

void Worker::Data()const
{
	cout << "Name: " << fullname << endl;
	cout << "Employee ID: " << id << endl;
}

void Worker::Get()
{
	getline(cin, fullname);
	cout << "Enter worker's ID: ";
	cin >> id;
	while (cin.get() != '\0')
	{
		continue;
	}
}

Worker::~Worker()
{

}


//Waiter: 

void Waiter::Set()
{
	cout << "Enter waiter's name: ";
	Worker::Get();
	Data();
}

void Waiter::Show()const
{
	cout << "Catagory: waiter" << endl;
	Worker::Data();
	Data(); //Waiter::Data()
}

void Waiter::Data()const
{
	cout << "Panache rating: " << panache << endl;
}

void Waiter::Get()
{
	cout << "Enter waiter's panache rating: ";
	cin >> panache;
	while (cin.get() != '\0')
	{
		continue;
	}
}

//Singer:

//对名字限定(通过类名和成员解析运算符)以确定其所属类
const char* Singer::pv[Singer::Vtypes] = { "other","alto","contralto","soprano","bass","baritone","tenor" };

void Singer::Set()
{
	cout << "Enter singer's name: ";
	Worker::Get();
	Get(); //Singer::Get()
}

void Singer::Show()const
{
	cout << "Catagory: singet\n";
	Worker::Data();
	Data(); //Singer::Data()
}

void Singer::Data()const
{
	cout << "Vocal range: " << pv[voice] << endl;
}

void Singer::Get()
{
	cout << "Enter number for singer's vocal range:\n";
	int i;
	for (i = 0; i < Vtypes; i++)
	{
		cout << i << ": " << pv[i] << " ";
		if(i % 4 == 3)
		{
			cout << endl;
		}
	}
	if(i % 4 != 0)
	{
		cout << '\n';
	}
	cin >> voice;
	while (cin.get() != '\n')
	{
		continue;
	}
}

//SingingWaiter

void SingingWaiter::Data()const
{
	Singer::Data();
	Waiter::Data();
}

void SingingWaiter::Get()
{
	Waiter::Get();
	Singer::Get();
}

void SingingWaiter::Set()
{
	cout<<"Enter singing waiter's name: ";
	Worker::Get();
	Get();  // SingingWaiter::Get()
}

void SingingWaiter::Show()const
{
	cout << "Catagory: singing waiter\n";
	Worker::Data();
	Data(); //SingingWaiter::Data()
}

//main.cpp


#include"class.h"
#include
#include
const int SIZE = 5;


int main()
{
	Worker* lolas[SIZE]; //基类指针数组,可以指向派生类指针
	int ct;
	for (ct = 0; ct < SIZE; ct++)
	{
		char choice;
		cout << "Enter the employee catagory: \n"
			<< "w: waiter s:singer "
			<< "t: singing waiter q:quit \n";
		cin >> choice;
		while (strchr("wstq", choice) == NULL)
		{
			cout << "Please enter a w, s, t, or q";
			cin >> choice;
		}
		if (choice == 'q')
		{
			break;
		}
		switch (choice)
		{
		case 'w':
			lolas[ct] = new Waiter;
			break;
		case 's':
			lolas[ct] = new Singer;
		case 't':
			lolas[ct] = new SingingWaiter;
			break;
		}
		cin.get();
		lolas[ct]->Set();
	}
	cout << "\nHere is your staff:\n";
	int i;
	for (i = 0; i < ct; i++)
	{
		cout << endl;
		lolas[i]->Show();
	}
	for (i = 0; i < ct; i++)
	{
		delete lolas[i];  // new 和 delete 配套   new -- delete  new [] -- delete []
	}
	cout << "Bye~" << endl;

	system("pause");
	return 0;
}

知识点:

1.引用多重继承的同时应当引用虚基类:虚基类使得从多个类派生出的对象只继承一个基类对象。

eg:

class Singer : virtual public Worker
class Waiter : public virtual worker

//virtual和public的顺序无关紧要

2.使用虚基类的构造函数规则

 1):C++在基类是虚的时候,将禁止信息通过中间类自动传递给基类,因此应当显式的调用所需的基类构造函数,否则将使用默认的基类构造函数。

eg:

SingingWaiter() { };
//MI的继承类需要显示的调用基类的构造函数,否则将自动调用基类的默认构造函数
SingingWaiter(const string& s, long n, int p = 0, int v = other) :Worker(s, n), Waiter(s, n, p), Singer(s, n, v) { };
SingingWaiter(const Worker& wk, int p = 0, int v = other) :Worker(wk), Waiter(wk, p), Singer(wk, v) { };
//参数类型为基类对象引用和指针时,传递的参数可以是其继承类对象的引用和指针
SingingWaiter(const Waiter& wk, int v = other) :Worker(wk), Waiter(wk), Singer(wk, v) { };  //此中的Waiter构造函数本应该接受两个参数,但其1第二个参数是一个默认参数,可以不传递参数.
SingingWaiter(const Singer& wk, int p = 0) :Worker(wk), Waiter(wk, p), Singer(wk) { };

 2):使用模块化方法来代替单继承的递增思想:即提供不同的基类组件,并在继承类中创建方法将这些组件组合起来。(派生类有有多个“父亲“,直接调用的函数可能在这些父亲中都存在,会出现多义性,所以需要使用模块化编程来指定特定的函数)

eg:

void SingingWaiter::Data()const
{
	Singer::Data();
	Waiter::Data();
}

void SingingWaiter::Get()
{
	Waiter::Get();
	Singer::Get();
}

void SingingWaiter::Set()
{
	cout<<"Enter singing waiter's name: ";
	Worker::Get();
	Get();  // SingingWaiter::Get()
}

void SingingWaiter::Show()const
{
	cout << "Catagory: singing waiter\n";
	Worker::Data();
	Data(); //SingingWaiter::Data()
}

3.cstring头文件中的strchr(a,b)函数,其中a为字符串,b为字符:该函数返回字符b在字符串a中第一次出现时的地址,若未出现则返回NULL。

4.类中包含纯虚函数时,该类为抽象基类,同时让派生类去实现纯虚函数,当虚基类的派生类在有纯虚函数未被定义之前不能进行实例化,必须实现所有纯虚函数后才能被实例化。(要确保同一虚函数在不同类中的声明完全一致)

参考文章:(9条消息) c++ 错误提示:不能使用抽象类对象_后青春了的博客-CSDN博客

5.虚基类的优先级:如果使用某个在多个类中均有声明的函数,非虚基类将会产生二义性的错误,而虚基类则会根据优先级选择函数。

  优先级:派生类 > 直接/间接祖先类

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/3002894.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-27
下一篇 2022-09-27

发表评论

登录后才能评论

评论列表(0条)

保存