一、 实验目的:
1、了解多态性的概念;
2、掌握运算符重载的基本方法;
3、掌握虚函数的定义和使用方法;
4、掌握纯虚函数和抽象类的概念和用法。
二、实验环境:
1、 PC计算机一台;
2、 Dev-C++开发环境。
三、实验原理:
当运算符重载函数作为成员函数实现:最左边的操作数必须是运算符的一个类对象或者是对该类对象的一个引用。函数的参数比原来的操作数个数少一个(后置的++、--除外,需要一个int形参),因为第一个操作数会被作为函数调用的目的对象,因此无需出现在参数表中,函数题可以直接访问第一个操作数的成员。当运算符重载函数作为友元函数实现:当访问类的private或protected数据成员时必须指定为友元函数。参数个数与原操作数个数相同,运算符的所有操作数必须显示通过参数传递。
所谓的接口,即将内部实现细节封装起来,外部用户用过预留的接口可以使用接口的功能而不需要知晓内部具体细节。C++中,通过类实现面向对象的编程,而在基类中只给出纯虚函数的声明,然后在派生类中实现纯虚函数的具体定义的方式实现接口,不同派生类实现接口的方式也不尽相同,从而实现多态
如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础类定义的函数(静态)如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作,这种做法很危险,也不符合生活习惯,在程序设计上也会给程序员带来困扰。如果基础类和衍生类定义了相同名称的成员函数,那么通过对象指针调用成员函数时,到底调用那个函数要根据指针的原型来确定,而不是根据指针实际指向的对象类型确定。
虚拟函数就是为了对“如果你以一个基础类指针指向一个衍生类对象,那么通过该指针,你只能访问基础类定义的成员函数”这条规则反其道而行之的设计。
四、实验内容:
1、构建一个复数类Complex,试对下列4个运算符进行重载:*(乘法),/(除法),++(自增运算),–(自减运算),其中要求要有成员重载形式和友元重载形式,而且,++运算符要求实现先加和后加两种形式,输出四种运算的运行结果。
2、假设有一种植物,在春天发芽,夏天开花,秋天结果,冬天凋落,请编程输出不同季节植物所呈现的特性。要求为:(1)编写一个接口PlantFeature,该接口中定义一个showFeature()方法;(2)定义4个类,分别实现PlantFeature接口,重写showFeature方法输出植物在不同季节的状态;(3)设置父类对象指针,指向子类对象,通过指针输出植物在不同季节的不同特性。
五、实验代码及结果(程序运行结果请以截屏图给出):
- 构建一个复数类Complex
#include <iostream>
#include <cmath>
using namespace std;
class Complex{
private:
double real, imag;
public:
Complex(double r=0,double i=0);
friend Complex operator +(Complex c1,Complex c2);
friend Complex operator -(Complex c1,Complex c2);
Complex operator ++();
Complex operator ++(int);
Complex operator --();
friend Complex operator *(Complex c1,Complex c2);
Complex operator /(const Complex& c);
void show();
};
Complex::Complex(double r,double i){
real=r;
imag=i;
};
Complex operator +(Complex c1,Complex c2){
double r=c1.real+c2.real;
double i=c1.imag+c2.imag;
return Complex(r,i);
};
Complex operator -(Complex c1,Complex c2){
double r=c1.real-c2.real;
double i=c1.imag-c2.imag;
return Complex(r,i);
};
Complex Complex::operator ++(){
double r=++real;
double i=++imag;
return Complex(r,i);
};
Complex Complex::operator ++(int){
double r=real++;
double i=imag++;
return Complex(r,i);
};
Complex Complex::operator --(){
double r=--real;
double i=--imag;
return Complex(r,i);
};
Complex operator *(Complex c1,Complex c2){
double r=c1.real * c2.real - c1.imag * c2.imag;
double i=c1.real * c2.imag + c1.imag * c2.real;
return Complex(r,i);
};
Complex Complex::operator /(const Complex& c){
double t = pow(c.imag,2) + pow(c.real,2);
double r=real * c.real + imag * c.imag;
double i=imag * c.real -real * c.imag;
return Complex(r/t,i/t);
};
void Complex::show(){
cout<<'('<<real<<','<<imag<<')'<<endl;
};
int main(){
Complex a(3,2),b(0,3),c;
c = a++;c.show();
c = --a;c.show();
c = ++a;c.show();
c = --a;c.show();
c = a + b;c.show();
c = a * b;c.show();
c = a / b;c.show();
system("pause");
return 0;
}
- 编写PlantFeature
#include <iostream>
using namespace std;
class PlantFeature{//define interface
private:
string Name;
public:
PlantFeature():Name("season"){};
virtual void showFeature(){
cout<<"season:";
}
};
//实现接口
class Spring:public PlantFeature{
private:
string na;
public:
Spring():na("Spring"){};
void showFeature(){
PlantFeature::showFeature();
cout<<"Spring"<<endl<<endl;
}
};
class Summer:public PlantFeature{
private:
string na;
public:
Summer():na("Summer"){};
void showFeature(){
PlantFeature::showFeature();
cout<<"Summer"<<endl<<endl;
}
};
class Autumn:public PlantFeature{
private:
string na;
public:
Autumn():na("Autumn"){};
void showFeature(){
PlantFeature::showFeature();
cout<<"Autumn"<<endl<<endl;
}
};
class Winter:public PlantFeature{
private:
string na;
public:
Winter():na("Winter"){};
void showFeature(){
PlantFeature::showFeature();
cout<<"Winter"<<endl<<endl;
}
};
int main(){
Spring sp;
Summer su;
Autumn au;
Winter wi;
PlantFeature *p;
p=&sp;
p->showFeature();
p=&su;
p->showFeature();
p=&au;
p->showFeature();
p=&wi;
p->showFeature();
system("pause");
return 0;
}
六、实验小结:
当定义一个指向子类实例的父类指针的时候,内存中实例化了子类,由于子类继承了父类,因此内存中的子类里包含父类的所有成员。但由于申明的是父类指针,因此该指针不能够访问子类的成员,而只能访问父类的成员。然而在父类里可以声明纯虚函数和定义虚函数,使用父类指针访问虚函数或纯虚函数的时候,访问到的是子类里重写的函数。当然,对于虚函数,如果子类里没有对其重写的话,仍然访问到父类里定义的虚函数。可见虚函数和纯虚函数的却别仅仅在于:纯虚函数没有定义,只有声明。