天天看点

c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

目录

  • 前言
  • 虚函数
  • 虚基类
  • 虚继承与多继承
  • 题目
    • 题目1
      • 输入
      • 输出
      • 样例输入
      • 样例输出
      • 代码
    • 题目2
      • 输入
      • 输出
      • 样例输入
      • 样例输出
      • 代码

前言

继续复习c++

虚函数

使用虚函数使得不同派生类使用基类指针调用时能够得到行为一致性的保证。这听起来有点抽象,意思是:

如果将派生类地址赋值给基类指针,再调用派生类中的函数,会失效,还是会调用基类中的同名函数。而基类中使用virtual关键字修饰的函数,在指针调用时则不会有这个问题。

详细请看:C++虚函数简单讲解

未使用虚函数,不能正确调用

class animal
{
public:
	void speak(){cout<<"animal speak!"<<endl;}	
};

class cat : public animal
{
public:
	void speak(){cout<<"cat speak!"<<endl;}		
};

int main()
{
	animal* a = new cat();
	a->speak();

	return 0;
}
           
c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

使用虚函数,正确调用实现多态

class animal
{
public:
	virtual void speak(){cout<<"animal speak!"<<endl;}	
};

class cat : public animal
{
public:
	void speak(){cout<<"cat speak!"<<endl;}		
};

int main()
{
	animal* a = new cat();
	a->speak();

	return 0;
}
           
c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

虚基类

虚基类又名抽象类,只包含虚函数。虚函数未被实现,需要用

xxx = 0

来修饰

继承一个虚基类需要实现其所有的虚函数,这起到了规范化的作用,因为有些对象必须实现特定的函数,否则无法正确运行。

如果未实现虚基类所有虚函数,那么会报错。

c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

下面的代码演示了继承一个抽象类,并且实现其抽象方法的过程

class animal
{
public:
	virtual void speak() = 0;
};

class cat : public animal
{
public:
	void speak(){cout<<"cat speak!"<<endl;}		
};

int main()
{
	animal* a = new cat();
	a->speak();

	return 0;
}
           

虚继承与多继承

不同于其他面向对象语言,c++支持多继承,即一个类可以继承很多基类。

在继承时,使用逗号分隔,即可实现继承多个对象。继承的本质是将基类对象作为成员创建。如下图展示了多继承时基类的创建关系

class cat
{
public:
	cat(){cout<<"cat对象被创建"<<endl;}
};

class people
{
public:
	people(){cout<<"people对象被创建"<<endl;}
};

class CatPeople : public cat, people
{
public:
	CatPeople(){cout<<"CatPeople对象被创建"<<endl;}
};

int main()
{
	CatPeople cp;

	return 0;
}
           
c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

可是如果有如下的继承结构,即多继承的基类AB继承自同一基类BASE

那么BASE会被创建两次。详情请:C++虚继承简单讲解。如下的代码演示了这一特性:

(其中BASE=animal,A=cat,B=people,C=CatPeople)

class animal
{
public:
	animal(){cout<<"animal对象被创建"<<endl;}
};

class cat : public animal
{
public:
	cat(){cout<<"cat对象被创建"<<endl;}
};

class people : public animal
{
public:
	people(){cout<<"people对象被创建"<<endl;}
};

class CatPeople : public cat, people
{
public:
	CatPeople(){cout<<"CatPeople对象被创建"<<endl;}
};

int main()
{
	CatPeople cp;

	return 0;
}
           
c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

这造成了额外的开销,而且当animal类的变量需要赋值的时候,会发生歧义问题,即不知道赋值给哪一个animal对象。

c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

如图:歧义问题的编译报错

c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

如果用virtual来修饰继承,即虚继承,那么将会只创建一次基类变量,赋值也不存在歧义问题:

class animal
{
public:
	int age;
	animal(){cout<<"animal对象被创建"<<endl;}
};

class cat : virtual public animal
{
public:
	cat(){cout<<"cat对象被创建"<<endl;}
};

class people : virtual public animal
{
public:
	people(){cout<<"people对象被创建"<<endl;}
};

class CatPeople : public cat, people
{
public:
	CatPeople(){cout<<"CatPeople对象被创建"<<endl; age=123;}
};

int main()
{
	CatPeople cp;

	return 0;
}
           
c++复习(3)虚函数,虚基类,虚继承与多继承前言虚函数虚基类虚继承与多继承题目

题目

题目1

编写一个程序,定义抽象基类Shape,在Shape类中定义虚函数Area();由它派生出3个派生类:Circle(圆形)、Square(正方形)、Rectangle(矩形)。用虚函数分别计算几种图形面积。

1、要求输出结果保留两位小数。

2、要求用基类指针数组,使它每一个元素指向每一个派生类对象。

输入

测试数据的组数 t

第一组测试数据中圆的半径

第一组测测试数据中正方形的边长

第一组测试数据中矩形的长、宽

第 t 组测试数据中圆的半径

第 t 组测测试数据中正方形的边长

第 t 组测试数据中矩形的长、宽

输出

第一组数据中圆的面积

第一组数据中正方形的面积

第一组数据中矩形的面积

第 t 组数据中圆的面积

第 t 组数据中正方形的面积

第 t 组数据中矩形的面积

样例输入

2
1.2
2.3
1.2 2.3
2.1
3.2
1.23 2.12
           

样例输出

4.52
5.29
2.76
13.85
10.24
2.61
           

代码

#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <cmath> 
#include <iomanip>
#include <vector>
#include <set>

#define PI 3.1415926

using namespace std;

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

class Circle : public Shape
{
private:
	double r;
public:
	Circle(){}
	Circle(double R){r=R;}
	virtual double Area(){return PI*r*r;}
};

class Square : public Shape
{
private:
	double r;
public:
	Square(){}
	Square(double R){r=R;}
	virtual double Area(){return r*r;}
};

class Rectangle : public Shape
{
private:
	double w,h;
public:
	Rectangle(){}
	Rectangle(double W, double H){w=W;h=H;}
	virtual double Area(){return w*h;}
};

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		Shape* shapes[3];
		double r,w,h;
		cin>>r;
		shapes[0] = new Circle(r);
		cin>>r;
		shapes[1] = new Square(r);
		cin>>w>>h;
		shapes[2] = new Rectangle(w,h);
		
		for(int i=0; i<3; i++)
		{
			cout<<fixed<<setprecision(2)<<shapes[i]->Area()<<endl;
		}
	}

	return 0;
}
           

题目2

1、建立如下的类继承结构:

  1. 定义一个人员类CPeople,其属性(保护类型)有:姓名、性别、年龄;
               
  2. 从CPeople类派生出学生类CStudent,添加属性:学号和入学成绩;
               
  3. 从CPeople类再派生出教师类CTeacher,添加属性:职务、部门;
               
  4. 从CStudent和CTeacher类共同派生出在职研究生类CGradOnWork,添加属性:研究方向、导师;
               

2、分别定义以上类的构造函数、输出函数print及其他函数(如需要)。

3、在主函数中定义各种类的对象,并测试之。

输入

第一行:姓名性别年龄

第二行:学号成绩

第三行:职务部门

第四行:研究方向导师

输出

第一行:People:

第二行及以后各行:格式见Sample

样例输入

wang-li m 23
2012100365 92.5
assistant computer
robot zhao-jun
           

样例输出

People:
Name: wang-li
Sex: m
Age: 23

Student:
Name: wang-li
Sex: m
Age: 23
No.: 2012100365
Score: 92.5

Teacher:
Name: wang-li
Sex: m
Age: 23
Position: assistant
Department: computer

GradOnWork:
Name: wang-li
Sex: m
Age: 23
No.: 2012100365
Score: 92.5
Position: assistant
Department: computer
Direction: robot
Tutor: zhao-jun
           

代码

#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <cmath> 
#include <iomanip>
#include <vector>
#include <set>

#define PI 3.1415926

using namespace std;

class People
{
protected:
	string name, sex, age;
public:
	People(){}	
	People(string Name, string Sex, string Age){name=Name;sex=Sex;age=Age;}
	friend ostream& operator << (ostream& os, People& p)
	{
		cout<<"People:"<<endl;
		cout<<"Name: "<<p.name<<endl;
		cout<<"Sex: "<<p.sex<<endl;
		cout<<"Age: "<<p.age<<endl;
	}
};

class Student : virtual public People
{
protected:
	string number, score;	
public:
	Student(){}
	Student(string na, string se, string ag, string nu, string sc)
	{
		name=na; sex=se; age=ag; number=nu; score=sc;
	}
	friend ostream& operator << (ostream& os, Student& p)
	{
		cout<<"Student:"<<endl;
		cout<<"Name: "<<p.name<<endl;
		cout<<"Sex: "<<p.sex<<endl;
		cout<<"Age: "<<p.age<<endl;
		cout<<"No.: "<<p.number<<endl;
		cout<<"Score: "<<p.score<<endl;
	}
};

class Teacher : virtual public People
{
protected:
	string department, position;	
public:
	Teacher(){}
	Teacher(string na, string se, string ag, string de, string po)
	{
		name=na; sex=se; age=ag; department=de; position=po;
	}
	friend ostream& operator << (ostream& os, Teacher& p)
	{
		cout<<"Teacher:"<<endl;
		cout<<"Name: "<<p.name<<endl;
		cout<<"Sex: "<<p.sex<<endl;
		cout<<"Age: "<<p.age<<endl;
		cout<<"Position: "<<p.position<<endl;
		cout<<"Department: "<<p.department<<endl;
	}
};

class GardOnWork : public Teacher, Student
{
protected:
	string direction, tutor;
public:
	GardOnWork(){}
	GardOnWork(string na,
			   string se, 
			   string ag, 
			   string nu, 
			   string sc, 
			   string de, 
			   string po,
			   string di,
			   string tu)
	{
		name=na; sex=se; age=ag; number=nu; score=sc; department=de; position=po; direction=di; tutor=tu;
	}
	friend ostream& operator << (ostream& os, GardOnWork& p)
	{
		cout<<"Teacher:"<<endl;
		cout<<"Name: "<<p.name<<endl;
		cout<<"Sex: "<<p.sex<<endl;
		cout<<"Age: "<<p.age<<endl;
		cout<<"No.: "<<p.number<<endl;
		cout<<"Score: "<<p.score<<endl;
		cout<<"Position: "<<p.position<<endl;
		cout<<"Department: "<<p.department<<endl;
		cout<<"Direction: "<<p.direction<<endl;
		cout<<"Tutor: "<<p.tutor<<endl;
	}
};

int main()
{
	string na, se, ag, nu, sc, de, po, di, tu;
	cin>>na>>se>>ag>>nu>>sc>>po>>de>>di>>tu;
	
	People p1 = People(na, se, ag);
	cout<<p1<<endl;
	
	Student p2 = Student(na, se, ag, nu, sc);
	cout<<p2<<endl;
	
	Teacher p3 = Teacher(na, se, ag, de, po);
	cout<<p3<<endl;
	
	GardOnWork p4 = GardOnWork(na, se, ag, nu, sc, de, po, di, tu);
	cout<<p4<<endl;

	return 0;
}
           

继续阅读