(C++)PTA:多态性 虚函数

(C++)PTA:多态性 虚函数

相关知识点

1、虚函数的工作原理

(引用C++ Primer Plus 13.4小节)
C++规定了虚函数的行为,并将实现方法留给了编译器,使得编写程序的人不需要知道实现方法就可以使用虚函数。但是了解虚函数的工作原理有助于更好地理解概念,因此,这里对其进行介绍。
通常,编译器处理虚函数的方法是:给每个对象添加一个隐藏成员。隐藏成员中保存了一个指向函数地址数组的指针。这种数组称为虚函数表( virtual function table, vtbl)。 虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址:如果派生类没有重新定义虚函数,该vtbl将保存函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址也将被添加到vtbl中。注意,无论类中包含的虚函数是1个还是10个,都只需要在对象中添加1个地址成员,只是表的大小不同而已。

2、一些特殊函数的虚函数有无情况
  • 构造函数:不可以声明为虚函数(派生类构造函数将使用基类构造函数)
  • 析构函数:可以声明为虚函数,除非类不用做基类(通常应给基类提供一个虚拟析构函数,即使它并不需要析构函数)
  • 友元函数:不可以声明为虚函数(友元函数不是类的成员)

6-1 汽车收费(多态) (10 分)

现在要开发一个系统,管理对多种汽车的收费工作。 给出下面的一个基类框架

class Vehicle
{
protected:
string NO;
public:
Vehicle(string n){
NO = n;
}
virtual int fee()=0;//计算应收费用
};

以Vehicle为基类,构建出Car、Truck和Bus三个类。
Car的收费公式为: 载客数8+重量2
Truck的收费公式为:重量5
Bus的收费公式为: 载客数
3
生成上述类并编写主函数
主函数根据输入的信息,相应建立Car,Truck或Bus类对象,对于Car给出载客数和重量,Truck给出重量,Bus给出载客数。假设载客数和重量均为整数

输入格式:第一行输入测试用例数。接着每个测试用例占一行,每行给出汽车的基本信息,第一个数据为当前汽车的类型:1为car,2为Truck,3为Bus。第二个数据为它的编号,接下来Car是载客数和重量,Truck要求输入重量,Bus要求输入载客数。

要求输出各车的编号和收费。
裁判测试程序样例:

#include<iostream>
#include <string>
using namespace std;
class Vehicle
{
protected:
    string NO;//编号
public:
    Vehicle(string n){	    NO = n;  }
    virtual int fee()=0;//计算应收费用
};

/* 请在这里填写答案 */

int main()
{
    Car c("",0,0);
    Truck t("",0);
    Bus b("",0);
    int i, repeat, ty, weight, guest;
    string no;
    cin>>repeat;
    for(i=0;i<repeat;i++){
        cin>>ty>>no;
        switch(ty){
            case 1: cin>>guest>>weight; c=Car(no, guest, weight); cout<<no<<' '<<c.fee()<<endl; break;
            case 2: cin>>weight; t=Truck(no, weight); cout<<no<<' '<<t.fee()<<endl; break;
            case 3: cin>>guest; b=Bus(no, guest); cout<<no<<' '<<b.fee()<<endl; break;
        }
    }
    return 0;
}

输入样例:
4
1 002 20 5
3 009 30
2 003 50
1 010 17 6
输出样例:
002 170
009 90
003 250
010 148

代码补充如下:
class Car:public Vehicle {
	public:
		int guest,weight;
		Car(string NO1,int guest1,int weight1):Vehicle(NO1) {
			weight=weight1;
			guest=guest1;
		}
		int fee() {
			return (8*guest+2*weight);
		}
};
class Truck:public Vehicle {
	public:
		int weight;
		Truck(string NO1,int weight1):Vehicle(NO1) {
			weight=weight1;
		}
		int fee() {
			return 5*weight;
		}
};
class Bus:public Vehicle {
	public:
		int guest;
		Bus(string no1,int guest1):Vehicle(no1) {
			guest=guest1;
		}
		int fee() {
			return 3*guest;
		}
};

6-2 抽象类Shape (10 分)

请编写一个抽象类Shape,包括两个纯虚函数,分别为计算面积getArea()和计算周长getPerim()。通过Shape类派生出矩形类Rectangle和圆类Circle,并计算各自的面积和周长。

测试用例具体要求:输入1表示测试矩形类,之后输入矩形长和宽。输入2表示测试圆类,之后输入圆半径。

Shape类定义如下:

class Shape {
	public:
		virtual double getArea()=0;
		virtual double getPerim()=0;
};

裁判测试程序样例:

#include <iostream>
using namespace std;
const double PI=3.14;

class Shape {
	public:
		virtual double getArea()=0;
		virtual double getPerim()=0;
};

/* ------请在这里填写答案 ------*/

int main() {
	Shape *p;
	int n;
	double w,h,r;
	scanf("%d",&n);
	switch(n) {
		case 1: {
			cin>>w>>h;
			Rectangle rect(w,h);
			cout<<"area="<<rect.getArea()<<endl;
			cout<<"perim="<<rect.getPerim()<<endl;
			break;
		}
		case 2: {
			cin>>r;
			Circle c(r);
			cout<<"area="<<c.getArea()<<endl;
			cout<<"perim="<<c.getPerim()<<endl;
			break;
		}
	}

	return 0;
}

输入样例1:
在这里给出一组输入。例如:

1
4 5
输出样例1:
在这里给出相应的输出。例如:

area=20
perim=18

输入样例2:
在这里给出一组输入。例如:

2
5
输出样例2:
在这里给出相应的输出。例如:

area=78.5
perim=31.4

代码补充如下:
class Circle : public Shape {
	public:
		Circle(double r) {
			radius=r;
		}
		double getArea() {
			return (PI * radius * radius);
		}
		double getPerim() {
			return (2*PI * radius);
		}
	private:
		double radius;
};

class Rectangle : public Shape {
	public:
		Rectangle(double width1,double height1) {
			width=width1;
			height=height1;
		}
		double getArea() {
			return (width*height);
		}
		double getPerim() {
			return (2*width+2*height);
		}
	private:
		double width;
		double height;
};

6-3 虚函数的应用 (15 分)

补充下列代码,使得程序的输出为:
A:3
A:15
B:5
3
15
5

类和函数接口定义:
参见裁判测试程序样例中的类和函数接口。
裁判测试程序样例:

#include <iostream>
using namespace std;
class CMyClassA {
    int val;
public:
    CMyClassA(int);
    void virtual print();
};
CMyClassA::CMyClassA(int arg) {
    val = arg;
    printf("A:%d\n", val);
}
void CMyClassA::print() {
    printf("%d\n", val);
    return;
}

/* 在这里填写代码 */

int main(int argc, char** argv) {
    CMyClassA a(3), *ptr;
    CMyClassB b(5);
    ptr = &a;
    ptr->print();
    a = b;
    a.print();
    ptr = &b;
    ptr->print();
    return 0;
}

输入样例:
None
输出样例:
A:3
A:15
B:5
3
15
5

代码补充如下:
class CMyClassB :public CMyClassA {
	public:
		int val2;
		CMyClassB(int x) :CMyClassA(3 * x), val2(x) {
			printf("B:%d\n", val2);
		}
		void print() {
			printf("%d\n", val2);
		}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值