c++第五次作业类的多态
2019-10-27 19:48 myself914 阅读(160) 评论(0) 编辑 收藏 举报类的多态
···重载多态、包含多态、强制多态和参数多态
···重点介绍重载多态中的
运算符重载和包含多态 |
一、运算符重载
1、运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同的类型数据时导致不同的行为。
2、重载形式:类的非静态成员函数和非成员函数(当以非成员函数形式时,有时需要访问运算符参数所涉及类的私有成员,这时可以把函数声明为类的友元函数)
3、语法形式:
返回类型 operator 运算符(形参表)
{
函数体
}
运算符重载为成员函数
···
#include<iostream>
using namespace std;
class Counter
{
public:
Counter(int i=0)
{
count=i;
}
Counter operator+(const Counter &c) const;
int display()
{
return count;
}
private:
int count;
};
Counter Counter::operator+(const Counter &c) const
{
return Counter(count+c.count);
}
int main()
{
Counter c1(9),c2(7),c3;
cout<<"c1="<<c1.display()<<endl;
cout<<"c2="<<c2.display()<<endl;
c3=c1+c2;//c3=c1.operator-(c2)
cout<<"c1+c2="<<c3.display()<<endl;
return 0;
}
···
运行结果:
运算符重载为非成员函数
···
#include<iostream>
using namespace std;
class Complex
{
public:
Complex(double r=0.0,double i=0.0)
{
real=r;
imag=i;
}
friend Complex& operator++(Complex &c);
friend Complex operator++(Complex &c,int);
void display()
{
cout<<"("<<real<<","<<imag<<")"<<endl;
}
private:
double real;
double imag;
};
Complex& operator++(Complex &c)
{
c.imag++;
c.real++;
return c;
}
Complex operator++(Complex &c,int)
{
Complex old=c;
++c;
return old;
}
int main()
{
Complex c1(6,8),f,d;
cout<<"first time output"<<endl;
c1.display();
cout<<"后置单目后:"<<endl;
f=c1++;
f.display();
cout<<"前置单目后:"<<endl;
d=++c1;
d.display();
return 0;
}
···
运行结果:
从上述两个实验可以看出这两种重载形式的区别:重载为类的成员函数时,第一个操作数会被作为函数调用目的对象,所以无须出现在参数列表中,函数的参数个数比原来的操作数个数要少一个;而重载为非成员函数时,运算符的所有操作数必须显示通过参数传递
二、包含多态
(一)、虚函数
问题:用基类类型的指针指向派生类对象,但是当用它访问该对象时,访问到的只是从基类继承的同名成员,怎样可以访问到派生类中的同名成员呢?
包含多态中的虚函数可以解决这一问题 |
···在基类中将这个同名函数说明为虚函数。
声明语法:virtual 函数类型 函数名(形参表)
举例如下:
···
#include<iostream>
using namespace std;
class BaseClass
{
public:
virtual void fun1() const;
void fun2()
{
cout<<"output BaseClass2"<<endl;
}
};
void BaseClass::fun1() const
{
cout<<"output BaseClass1"<<endl;
}
class DerivedClass:public BaseClass
{
public:
void fun1() const
{
cout<<"output DerivedClass1"<<endl;
}
void fun2()
{
cout<<"output DerivedClass2"<<endl;
}
};
int main()
{
DerivedClass a;
BaseClass *b;
DerivedClass *c;
b=&a;
b->fun1();
b->fun2();
//b->BaseClass::fun1()
c=&a;
c->fun1();
c->fun2();
return 0;
}
···
1、对比使用虚函数的fun1和没有使用虚函数的fun2,结果是:
,可以看出基类指针*b在访问虚函数fun1时,访问的时派生类的同名函数,而访问fun2时访问的是从基类继承来的fun2函数。
2、如果想要指针仍然可以访问基类中被派生类覆盖的成员函数,可以使用“::”进行限定。 将上述例子中改为:
,结果为:
,可以看出加了限定后可以访问基类中被覆盖的虚函数。
(二)、虚析构函数
如果有可能通过基类指针调用对象的析构函数(通过delete),就需要让基类的析构函数成为虚函数,否则会产生不确定的后果,通过以下例子对比说明:
···
#include<iostream>
using namespace std;
class Base
{
public:
virtual ~Base();
//~Base();
};
Base::~Base()
{
cout<<"Base destructor"<<endl;
}
class Derived:public Base
{
public:
Derived();
~Derived();
private:
int *p;
};
Derived::Derived()
{
p = new int(0);
}
Derived::~Derived()
{
cout << "Derived destructor" << endl;
delete p;
}
void fun(Base *b)
{
delete b;
}
int main()
{
Base *b = new Derived();
fun(b);
return 0;
}
···
未声明为虚析构函数时的结果:
声明为虚析构函数时的结果:
原因是:通过基类指针删除派生类对象时调用的是基类的析构函数,派生类的析构函数没有被执行,因此派生类对象中动态分配的内存空间没有得到释放,程序如果持续发生这样的错误很危险,避免错误的有效方法就是将析构函数声明为虚函数。****************
(三)、纯虚函数与抽象
问题:在基类中声明与派生类相同原型的函数,将它们作为虚函数,这样派生类中的这几个函数就是对基类相应函数的覆盖,通过基类指针调用时,派生类函数被调用,然而基类中的这些函数可不可以不给出实现,只是先在基类中说明函数原型,再在派生类中给出具体实现呢?
纯虚函数可以实现其功能 |
···
#include<iostream>
using namespace std;
class Shape
{
public:
virtual double getArea() const=0;
virtual double getPerim() const=0;
};
class Rectangle:public Shape
{
public:
Rectangle(double len=0.0,double wid=0.0)
{
length=len;
width=wid;
}
double getArea() const
{
return length*width;
}
double getPerim() const
{
return 2*(length+width);
}
private:
double length;
double width;
};
class Circle:public Shape
{
public:
Circle(double r)
{
ridus=r;
}
double getArea() const
{
return 3.14*ridus*ridus;
}
double getPerim() const
{
return 2*3.14*ridus;
}
private:
double ridus;
};
void showArea(Shape *a)
{
cout<<"the area is:"<<a->getArea()<<endl;
}
void showPerim(Shape *a)
{
cout<<"the perim is:"<<a->getPerim()<<endl;
}
int main()
{
//Shape a;
Rectangle b(5.1,7.9);
Circle c(3.2);
showArea(&b);
showPerim(&b);
showArea(&c);
showPerim(&c);
return 0;
}
···
1、如果定义一个抽象类的对象:
,所以抽象类不能实例化
2、如果上述例子Rectangle不给出getArea()的实现:结果
,所以派生类不给出所有纯虚函数的实现的话,仍然是个抽象类,不能实例化。
3、正确的运行结果: