面向对象程序设计|多态与虚函数

题目一:员工工资(虚函数与多态)

题目描述:

某公司员工的属性有:姓名、职位、级别、工作年限,级别和年限都是非负整数,否则显示错误。包含方法有:构造函数,计算工资的方法(salary())。

员工职位分为三种:Employee、Teamleader、Manager,其他职位类型显示错误。

三种职位员工的区别在于计算工资的方法不同:

1. Employee的每月工资 = 1000 + 500*级别 + 50*工作年限

2. Teamleader的每月工资 = 3000 + 800*级别 + 100*工作年限

3. Manager的每月工资 = 5000 + 1000 * (级别+工作年限)

计算工资的方法返回每个员工的工资数。

要求:以普通员工为基类,组长和经理继承基类,程序中只能使用基类指针指向对象与调用对象的方法。

输入要求:

测试案例的个数 t

每行输入一个员工的信息:包括姓名、职位、级别、工作年限

输出要求:

输出相应员工的信息

如有错误信息,则输出错误信息,若职位信息与级别和年限信息同时出错,仅输出职位错误信息

输入样例:

5
zhangsan Employee 4 5
lisi Teamleader 4 5
Wangwu Manager 4 5
chenliu Precident 4 5
xiaoxiao Manager -1 5

输出样例:

zhangsan:Employee,Salary:3250
lisi:Teamleader,Salary:6700
Wangwu:Manager,Salary:14000
error position.
error grade or year.

代码示例:

#include
#include
#include
#include 
#include
#include
using namespace std;

class Staff
{
protected:
	string name, post;
	int year, level;
public:
	Staff() {}
	Staff(string nn, string pp, int yy, int ll) :name(nn), post(pp), year(yy), level(ll) {}
	virtual int getSalary()
	{
		return 0;
	}
	virtual void display() {}
};


class Employee :public Staff
{
public:
	Employee() {}
	Employee(string nn, string pp, int yy, int ll) :Staff(nn, pp, yy, ll) {}
	virtual int getSalary()
	{
		return 1000 + 500 * level + 50 * year;
	}
	virtual void display()
	{
		cout << name << ":Employee,Salary:" << getSalary() << endl;
	}
};

class Teamleader : public Staff
{
public:
	Teamleader() {}
	Teamleader(string nn, string pp, int yy, int ll) :Staff(nn, pp, yy, ll) {}
	virtual int getSalary()
	{
		return 3000 + 800 * level + 100 * year;
	}
	virtual void display()
	{

		cout << name << ":Teamleader,Salary:" << getSalary() << endl;
	}
};

class Manager :public Staff
{
public:
	Manager() {}
	Manager(string nn, string pp, int yy, int ll) :Staff(nn, pp, yy, ll) {}
	virtual int getSalary()
	{
		return 5000 + 1000 * level + 1000 * year;
	}
	virtual void display()
	{
		cout << name << ":Manager,Salary:" << getSalary() << endl;
	}
};

int main()
{
	int t;
	cin >> t;
	Staff* s;//用基类指针指向对象与调用对象的方法
	while (t--)
	{
		string na, po;
		int lv, ye;
		cin >> na >> po >> lv >> ye;
		if (po != "Manager" && po != "Teamleader" && po != "Employee")
		{
			cout << "error position." << endl;
		}
		else if (lv < 0 || ye < 0)
		{
			cout << "error grade or year." << endl;
		}
		else
		{
			if (po == "Employee")
			{
				Employee e(na, po, ye, lv);
				s = &e;//指针指向对象
				s->display();//调用对象,下面同理
			}
			else if (po == "Teamleader")
			{
				Teamleader t(na, po, ye, lv);
				s = &t;
				s->display();
			}
			else if (po == "Manager")
			{
				Manager m(na, po, ye, lv);
				s = &m;
				s->display();
			}
		}
	}
	return 0;
}

掌握基类指针指向对象与调用对象的方法!!

题目二:支票账户(虚函数与多态)

题目描述:

某银行的支票账户分为两类,一类为基本支票账户BaseAccount,另一类为具有透支保护特性的BasePlus支票账户。

BaseAccount支票账户的信息包括:客户姓名(name)、账户(account)、当前结余(balance);BaseAccount支票账户可以执行的操作包括:存款(deposit)、取款(withdraw)、显示账户信息(display)。注意:取款金额不能透支,否则显式出错信息“insufficient”。

BasePlus支票账户除包含BaseAccount的所有信息外,还包括以下信息:透支上限(limit:默认为5000),当前透支总额(limit_sum);BasePlus支票账户可执行的操作与BaseAccount相同,但有两种操作的实现不同:(1)对于取款操作,可以在透支上限范围内透支,超过则显示出错信息“insufficient”;(2)对于显示操作,必须显示BasePlus的其他信息。

请实现BaseAccount类和BasePlus类,其中BasePlus类继承于BaseAccount类,注意BaseAccount账户名称以BA开头,BasePlus账户名称以BP开头。

要求只使用一个基类指针,指向所建立的对象,然后使用指针调用类中的方法。

输入要求:

测试案例组数 t

第一组测试数据:

第一行输入账户信息:姓名 帐号 当前余额

第二行输入四个整数,表示对账户按顺序存款、取款、存款、取款

第二组测试数据:

.........

输出要求:

输出BaseAccount的信息

输出BasePlus的信息

输入样例:

4
Tom BA008 1000
1000 2000 1000 1200
Bob BP009 1000
1000 2000 1000 7000
May BA001 2000
500 1000 500 1000
Lily BP002 1000
500 2000 500 3000

输出样例:

insufficient
Tom BA008 Balance:1000
insufficient
Bob BP009 Balance:1000 limit:5000
May BA001 Balance:1000
Lily BP002 Balance:0 limit:2000

代码示例:

#include
#include
#include
#include 
#include
#include
using namespace std;

class BaseAccount
{
protected:
    string name, account;
    int balance;
public:
    BaseAccount() :balance(0) {}
    BaseAccount(string nn, string aa, int bb) :name(nn), account(aa), balance(bb) {}
    void deposit(int dd)
    {
        balance = balance + dd;
    }
    void virtual withdraw(int ww)
    {
        if (ww > balance)
        {
            cout << "insufficient" << endl;
        }
        else
        {
            balance -= ww;
        }
    }
    void virtual display()
    {
        cout << name << " " << account << " Balance:" << balance << endl;
    }
};

class BasePlus :public BaseAccount
{
    int limit;
    int limitsum;
public:
    BasePlus() :limit(5000) {}
    BasePlus(string nn, string aa, int bb) :BaseAccount(nn, aa, bb), limit(5000) {}
    void withdraw(int ww)
    {
        if (ww > (balance + limit))
            cout << "insufficient" << endl;
        else
        {
            if (ww > balance)
            {
                limit -= ww - balance;
                balance = 0;
            }
            else
            {
                balance -= ww;
            }
        }
    }
    void display()
    {
        cout << name << " " << account << " Balance:" << balance << " limit:" << limit << endl;
    }
};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        string na, ac;
        int ba;
        int d1, d2, w1, w2;
        BaseAccount* p;
        cin >> na >> ac >> ba;
        string a[6];
        a[1] = ac[1];//将字符串中的第1个字符赋值给另一个字符串的方法
        if (a[1] == "A")
        {
            p = new BaseAccount(na, ac, ba);//使用一个基类指针,指向所建立的对象,然后使用指针调用类中的第二种方法
            cin >> d1 >> w1 >> d2 >> w2;
            p->deposit(d1);
            p->withdraw(w1);
            p->deposit(d2);
            p->withdraw(w2);
            p->display();
        }
        else if (a[1] == "P")
        {
            p = new BasePlus(na, ac, ba);
            cin >> d1 >> w1 >> d2 >> w2;
            p->deposit(d1);
            p->withdraw(w1);
            p->deposit(d2);
            p->withdraw(w2);
            p->display();
        }
    }
    return 0;
}

注意使用一个基类指针,指向所建立的对象,然后使用指针调用类中的第二种方法。

题目三:计算宝宝帐户收益(多重继承)

题目描述:

定义一个类CPeople,具有身份号码(id,char[20])和姓名(name,char[10])两个数据成员,从CPeople类中再派生出CInternetUser类和CBankCustomer类,然后再从CInternetUser和CBankCustomer多重继承派生出CInternetBankCustomer类。

CInternetUser类有登录密码(password,char[20])属性和注册register(设置id, name和password),登录login(判断输入的id与password是否与对象注册的相同)成员函数。

CBankCustomer类有余额(balance,double)属性和开户openAccount(设置客户姓名和id),存款deposit,取款withdraw以及缺省的构造函数。

CInternetBankCustomer类包括有余额, 前一日余额, 当日收益,今日万元收益和上一日万元收益等5个数据成员,成员函数有缺省构造函数,存款和取款,设置万元收益,计算当日收益,登陆login(判断输入的id和密码是否与互联网用户的相同,同时从CBankCustomer继承的用户姓名和id要与从CInternetUser继承的相同)。CInternetBankCustomer类对象当日存款不计算收益,第2天开始才能计算收益,当日取款部分无收益。

可参照如下所示的主函数来测试并设计输入数据:

void main()
{
int t, no_of_days, i;
char i_xm[20], i_id[20], i_mm[20], b_xm[20], b_id[20], ib_id[20], ib_mm[20];
double money, interest;
char op_code;

//输入测试案例数t
cin >> t;
while (t--)
{
//输入互联网用户注册时的用户名,id,登陆密码
cin >> i_xm >> i_id >> i_mm;

//输入银行开户用户名,id
cin >> b_xm >> b_id;

//输入互联网用户登陆时的id,登陆密码
cin >> ib_id >> ib_mm;

CInternetBankCustomer ib_user;

ib_user.registerUser(i_xm, i_id, i_mm);
ib_user.openAccount(b_xm, b_id);

if (ib_user.login(ib_id, ib_mm) == 0)  //互联网用户登陆,若id与密码不符;以及银行开户姓名和id与互联网开户姓名和id不同
{
cout << "Password or ID incorrect" << endl;
continue;
}

//输入天数
cin >> no_of_days;
for (i=0; i < no_of_days; i++)
{
//输入操作代码, 金额, 当日万元收益
cin >> op_code >> money >> interest;
switch (op_code)
{
case 'S':  //从银行向互联网金融帐户存入
case 's':
if (ib_user.deposit(money) == 0)
{
cout << "Bank balance not enough" << endl;
continue;
}
break;
case 'T':  //从互联网金融转入银行帐户
case 't':
if (ib_user.withdraw(money) == 0)
{
cout << "Internet bank balance not enough" << endl;
continue;
}
break;
case 'D':  //直接向银行帐户存款
case 'd':
ib_user.CBankCustomer::deposit(money);
break;
case 'W':  //直接从银行帐户取款
case 'w':
if (ib_user.CBankCustomer::withdraw(money) == 0)
{
cout << "Bank balance not enough" << endl;
continue;
}
break;
default:
cout << "Illegal input" << endl;
continue;
}
ib_user.setInterest(interest);
ib_user.calculateProfit();
//输出用户名,id
//输出银行余额
//输出互联网金融账户余额
ib_user.print();
}
}
}

输入要求:

输入用户例数

输入第1个互联网用户注册时的用户名,id,登陆密码

输入第1个用户银行开户用户名,id

输入第1个互联网用户登陆时的id,登陆密码

输入第1个用户操作天数

循环输入操作代码(S,T,D,W)  金额  当日万元收益
......

输出要求:

输出第1个用户名,id
输出第1个用户银行余额
输出第1个互联网金融账户余额
......

输入样例:

2
zhangsan 1234567890 222222
zhangsan 1234567890
1234567890 222222
4
D 15000 0
s 8000 1.5
T 3000 1.55
w 2000 0
lisi 2014150000 abcdef
lisi 2014150000
2014150000 123456

输出样例:

Name: zhangsan ID: 1234567890
Bank balance: 15000
Internet bank balance: 0

Name: zhangsan ID: 1234567890
Bank balance: 7000
Internet bank balance: 8000

Name: zhangsan ID: 1234567890
Bank balance: 10000
Internet bank balance: 5001.2

Name: zhangsan ID: 1234567890
Bank balance: 8000
Internet bank balance: 5001.98

Password or ID incorrect

代码示例:

#include
#include
#include
#include 
#include
#include
using namespace std;

class People
{
protected:
    char id[20], name[10];
public:
    People() {}
    People(char nn[10], char ii[20])
    {
        strcpy(name, nn);
        strcpy(id, ii);
    }

};

class InternetUser :virtual public People
{
protected:
    char password[20];
public:
    InternetUser() {}
    InternetUser(char nn[10], char ii[20], char pp[20]) :People(nn, ii)
    {
        strcpy(password, pp);
    }
    void Register(char nn[10], char ii[20], char pp[20])
    {
        strcpy(name, nn);
        strcpy(id, ii);
        strcpy(password, pp);
    }
};

class BankCustomer :virtual public People
{
protected:
    double balance;
public:
    BankCustomer() {}
    void openAccount(char nn[10], char ii[20])
    {
        strcpy(name, nn);
        strcpy(id, ii);
        balance = 0;
    }
    void Deposit(double dd)
    {
        balance += dd;
    }
    int Withdraw(double ww)
    {
        if (balance - ww >= 0)
        {
            balance -= ww;
            return 1;
        }
        else
        {
            return 0;
        }
    }
};

class InternetBankCustomer :public InternetUser, public BankCustomer
{
protected:
    double balancei, balancey, profit, profitp, profity;
public:
    InternetBankCustomer()
    {
        balancei = 0.00;
        balancey = 0.00;
        profit = 0.00;
        profitp = 0.00;
        profity = 0.00;
    }
    int Login(char ii[20], char pp[20])
    {
        return ((!strcmp(ii, InternetUser::id)) && (!strcmp(pp, InternetUser::password))) && (!strcmp(InternetUser::id, BankCustomer::id) && !strcmp(InternetUser::name, BankCustomer::name));
    }
    int Deposit(double dd)
    {
        if (balance - dd >= 0)
        {
            balance -= dd;
            balancei += dd;
            return 1;
        }
        else
        {
            return 0;
        }
    }
    int Withdraw(double ww)
    {
        if (balancei - ww >= 0)
        {
            balancei -= ww;
            balance += ww;
            return 1;
        }
        else
        {
            return 0;
        }
    }
    void setInterest(double ii)
    {
        profity = profitp;
        profitp = ii;
    }
    void calculateProfit()
    {
        profit = profity * 0.0001 * balancey;
        balancei += profit;
        balancey = balancei;
    }
    void print()
    {
        cout << "Name: " << BankCustomer::name << " ID: " << BankCustomer::id << endl;
        cout << "Bank balance: " << balance << endl;
        cout << "Internet bank balance: " << balancei << endl;
        cout << endl;
    }
};

int main()
{
    int t, no_of_days, i;
    char i_xm[20], i_id[20], i_mm[20], b_xm[20], b_id[20], ib_id[20], ib_mm[20];
    double money, interest;
    char op_code;

    //输入测试案例数t
    cin >> t;
    while (t--)
    {
        //输入互联网用户注册时的用户名,id,登陆密码
        cin >> i_xm >> i_id >> i_mm;

        //输入银行开户用户名,id
        cin >> b_xm >> b_id;

        //输入互联网用户登陆时的id,登陆密码
        cin >> ib_id >> ib_mm;

        InternetBankCustomer ib_user;

        ib_user.Register(i_xm, i_id, i_mm);
        ib_user.openAccount(b_xm, b_id);

        if (ib_user.Login(ib_id, ib_mm) == 0)  //互联网用户登陆,若id与密码不符;以及银行开户姓名和id与互联网开户姓名和id不同
        {
            cout << "Password or ID incorrect" << endl;
            continue;
        }

        //输入天数
        cin >> no_of_days;
        for (i = 0; i < no_of_days; i++)
        {
            //输入操作代码, 金额, 当日万元收益
            cin >> op_code >> money >> interest;
            switch (op_code)
            {
            case 'S':  //从银行向互联网金融帐户存入
            case 's':
                if (ib_user.Deposit(money) == 0)
                {
                    cout << "Bank balance not enough" << endl;
                    continue;
                }
                break;
            case 'T':  //从互联网金融转入银行帐户
            case 't':
                if (ib_user.Withdraw(money) == 0)
                {
                    cout << "Internet bank balance not enough" << endl;
                    continue;
                }
                break;
            case 'D':  //直接向银行帐户存款
            case 'd':
                ib_user.BankCustomer::Deposit(money);
                break;
            case 'W':  //直接从银行帐户取款
            case 'w':
                if (ib_user.BankCustomer::Withdraw(money) == 0)
                {
                    cout << "Bank balance not enough" << endl;
                    continue;
                }
                break;
            default:
                cout << "Illegal input" << endl;
                continue;
            }
            ib_user.setInterest(interest);
            ib_user.calculateProfit();
            //输出用户名,id
            //输出银行余额
            //输出互联网金融账户余额
            ib_user.print();
        }
    }
    return 0;
}

有点麻烦,耐心看看

题目四:进位与借位(虚函数和多态)

题目描述:

某小学二年级的数学老师在教学生整数加减法运算时发现:班上的同学可以分成三类,第一类可以正确地完成加减法运算(GroupA);第二类可以正确地完成加法运算,但对于减法运算来说,总是忘记借位的处理(GroupB);第三类总是忘记加法的进位,也总是忘记减法的借位(GroupC)。(提示:小学二年级还没学负数。)

现在请模拟当老师在课堂提问某位同学时,同学会给出的回答。

实现时请基于下面的基类框架:

class Group

{

public:

virtual int add(int x, int y)=0;//输出加法的运算结果

virtual int sub(int x, int y)=0;//输出减法的运算结果

}

构建出GroupA, GroupB和GroupC三个派出类:

并编写主函数,要求主函数中有一个基类Group指针,通过该指针统一地进行add和sub运算。

输入要求:

第一行表示测试次数。从第二行开始,每个测试用例占一行,每行数据意义如下:学生类别(1为第一类学生,2为第二类学生,3为第三类学生)、第一个数、第二个数。

输出要求:

运算后的结果

输入样例:

3
1 79+81
2 81-79
3 183+69

输出样例:

160
12
142

代码示例:

#include
#include
#include
#include 
#include
#include
using namespace std;

class Group
{
protected:

public:
    virtual int add(int x, int y) = 0;//输出加法的运算结果
    virtual int sub(int x, int y) = 0;//输出减法的运算结果
};

class GroupA :public Group
{
public:
    virtual int add(int x, int y)
    {
        return x + y;
    }
    virtual int sub(int x, int y)
    {
        return x - y;
    }
};

class GroupB :public Group
{
public:
    virtual int add(int x, int y)
    {
        return x + y;
    }
    virtual int sub(int x, int y)
    {
        int xm[10], ym[10];
        int i;
        for (i = 0; x != 0 || y != 0; i++)
        {
            xm[i] = x % 10;
            ym[i] = y % 10;
            x /= 10;
            y /= 10;
        }
        int sm[10];
        for (int j = 0; j < i; j++)
        {
            if (xm[j] < ym[j])
            {
                sm[j] = xm[j] + 10 - ym[j];
            }
            else
            {
                sm[j] = xm[j] - ym[j];
            }
        }
        int sum = 0;
        for (int j = 0; j < i; j++)
        {
            sum += sm[j] * pow(10, j);
        }
        return sum;
    }
};

class GroupC :public Group
{
public:
    virtual int add(int x, int y)
    {
        int xm[10], ym[10];
        int i;
        for (i = 0; x != 0 || y != 0; i++)
        {
            xm[i] = x % 10;
            ym[i] = y % 10;
            x /= 10;
            y /= 10;
        }
        int sm[10];
        for (int j = 0; j < i; j++)
        {
            sm[j] = (xm[j] + ym[j]) % 10;
        }
        int sum = 0;
        for (int j = 0; j < i; j++)
        {
            sum += sm[j] * pow(10, j);
        }
        return sum;
    }
    virtual int sub(int x, int y)
    {
        int xm[10], ym[10];
        int i;
        for (i = 0; x != 0 || y != 0; i++)
        {
            xm[i] = x % 10;
            ym[i] = y % 10;
            x /= 10;
            y /= 10;
        }
        int sm[10];
        for (int j = 0; j < i; j++)
        {
            if (xm[j] < ym[j])
            {
                sm[j] = xm[j] + 10 - ym[j];
            }
            else
            {
                sm[j] = xm[j] - ym[j];
            }
        }
        int sum = 0;
        for (int j = 0; j < i; j++)
        {
            sum += sm[j] * pow(10, j);
        }
        return sum;
    }
};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        Group* g;
        int n, x, y;
        char c;
        cin >> n >> x >> c >> y;
        if (n == 1)
        {
            g = new GroupA;//无原始构造的基类指针指向对象
            if (c == '+')
            {
                cout << g->add(x, y) << endl;
            }
            else if (c == '-')
            {
                cout << g->sub(x, y) << endl;
            }
        }
        else if (n == 2)
        {
            g = new GroupB;
            if (c == '+')
            {
                cout << g->add(x, y) << endl;
            }
            else if (c == '-')
            {
                cout << g->sub(x, y) << endl;
            }
        }
        else if (n == 3)
        {
            g = new GroupC;
            if (c == '+')
            {
                cout << g->add(x, y) << endl;
            }
            else if (c == '-')
            {
                cout << g->sub(x, y) << endl;
            }
        }
    }
    return 0;
}

注意题目要求的算法!

题目五:求最大面积(虚函数和多态)

题目描述:

请编写程序,从图形数组中找出最大面积。基类框架如下所示:

class Geometry{

public:

virtual double getArea()=0; //计算面积,结果保留小数点后两位

};

以Geometry为基类,构建出Rect(矩形,数据成员为长和宽)和Circle(圆,数据成员为半径)两个类,重写getArea()方法,其他方法根据需要自拟。

写一个TotalArea类,该类结构如下:

class TotalArea{

public:

static void computerMaxArea(Geometry** t,int n);//t为基类二级指针,指向一个基类动态数组,数组的每个元素指向一个子类图形,n为数组的大小

};

生成上述四个类并编写主函数,结果保留两位小数。

输入要求:

第一行表示测试次数。从第二行开始,每个测试用例占一行,每行数据意义如下:图形类型(1为Rect(矩形),2为Circle(圆))、基本信息(Rect是长和宽,Circle是半径)。

输出要求:

最大图形的面积

输入样例:

3
1 3 4
2 5
2 6

输出样例:

最大面积=113.04

代码示例:

#include
#include
#include
#include 
#include
#include
using namespace std;

class Geometry
{
public:
    virtual double getArea() = 0; //计算面积,结果保留小数点后两位
};

class Rect :public Geometry
{
protected:
    double x, y;
public:
    Rect(double xx, double yy) :x(xx), y(yy) {}
    virtual double getArea()
    {
        return x * y;
    }
};

class Circle :public Geometry
{
protected:
    double r;
public:
    Circle(double rr) :r(rr) {}
    virtual double getArea()
    {
        return 3.14 * r * r;
    }
};

class TotalArea
{
public:
    static void computerMaxArea(Geometry** t, int n)
    {
        double maxarea = 0;
        for (int i = 0; i < n; i++)
        {
            if (t[i]->getArea() > maxarea)
            {
                maxarea = t[i]->getArea();
            }
        }
        cout << "最大面积=" << fixed << setprecision(2) << maxarea << endl;
    }
};

int main()
{
    int t;
    cin >> t;
    Geometry** geo = new Geometry * [t];
    for (int i = 0; i < t; i++)
    {
        int type;
        cin >> type;
        if (type == 1)
        {
            double x, y;
            cin >> x >> y;
            geo[i] = new Rect(x, y);
        }
        else if (type == 2)
        {
            double r;
            cin >> r;
            geo[i] = new Circle(r);
        }
    }
    TotalArea total;
    total.computerMaxArea(geo, t);//求最大面积
    delete[]geo;
    return 0;
}

注意二级指针的用法!

你可能感兴趣的:(Simple,C++,开发语言,C++,算法)