C++学习之多态
C++的类机制中有支持多态的技术来解决抽象编程,它用的是一种滞后易做图技术,
这种技术,通过预先设定其成员函数的虚函数性质,使得任何易做图该成员函数的未定类型的对象操作在编译时,都以一个不确定的指针特殊地“引命代发”来编码,
到了运行时,遇到确定类型的对象,才突然制定其真正的行为。即滞后到运行时,根据具体类型的对象来易做图成员函数,这样,辨别对象类型的工作就可以不用用户做了。
虚函数(Virtual Function)
1.多态条件(Polymorphism Condition)
使用类编程中,要能进行抽象编程,不随类的改动而改动,类机制必须解决这个问题,在C++中,就是虚函数机制。基类与派生类的同名操作。只要标记上virtual,则该操作便具有多态性。
如下代码所示:
[cpp]
#include <iostream>
using namespace std;
class Base
{
public:
virtual void fun()
{
cout << "In Base class" << endl;
}
};
class Sub : public Base
{
public:
virtual void fun()
{
cout << "In Sub class" << endl;
}
};
void test(Base& b)
{
b.fun();
}
int main()
{
Base bc;
Sub sc;
test(bc);
test(sc);
return 0;
}
代码输出如下:
[plain]
In Base class
In Sub class
上述代码中fun是Base类的虚函数,一旦标记了基类的函数为虚函数,则后面继承类中一切同名成员函数都编程了虚函数,在test函数中,b是Base类的引用性形参,Base类对象和Sub类对象都可以作为实参传给形参b。
如果函数参数是实际复制动作的传递,则子类对象完全变成基类对象了,这样,便不会有多态了。如将上述代码中的test函数参数改为如下形式时,
如下代码所示:
[cpp]
void test(Base b)
{
b.fun();
}
int main()
{
Base bc;
Sub sc;
test(bc);
test(sc);
return 0;
}
其输出则变为:
[plain]
In Base class
In Base class
因为对于这种参数的传递过程已经将对象的性质做了肯定的转变,而对于确定的对象,是没有选择操作可言的。因此,对于多态,仅仅对于对象的指针和引用的间接访问,才会发生多态现象。
2. 虚函数机理
在上述代码中,b.fun()函数调用显示出多样性,其编译不能立即确定fun的确切位置,即不能确定到底是调用基类Base的fun函数,还是子类Sub的fun函数。
当编译器看到fun的虚函数标志时,以放入虚函数表中,等到遇到b.fun()这个虚函数的调用时,便将该易做图操作滞后到运行中,以实际的对象类型来实际易做图其对应的成员函数操作。当然编译器不可能跟踪到运行的程序中去,而是在易做图操作b.fun()处避开函数调用,只做一个指向实际对象的成员函数的间接访问。如此,实际对象若是基类,则调用的就是基类成员函数,若是子类,则调用的就是子类的成员函数。当然,每一个实际的对象都必须额外占有一个指针空间,以指向类中的虚函数表。如下图所示。
从图中可以看处,用了虚函数的类,其对象的空间比不用虚函数的类多了一个指针的空间,由于涉及了其他的操作,包括间接访问虚函数,对象的指针偏移量计算等,所以在应用了虚函数后,会影响程序的运行效率。
3.虚函数的传播
虚函数在继承层次结构中总是会自动地从基类传播下去。因此,上述代码中Sub类中的成员函数fun的virtual说明可以省略,
例如下面的例子:
在一个平面形状类的体系中,基类shape有两个子类:圆Circle类和长方形Retangle类,专门负责求面积的Area函数在基类中设置为virtual就能使子类的响应同名函数虚拟化。
[plain]
#include<iostream>
#include <cmath>
using namespace std;
class Shape
{
protected:
double xCoord, yCoord;
public:
Shape(double x, double y)
{
xCoord = x;
yCoord = y;
}
virtual double area()const
{
return 0.0;
}
};
class Circle : public Shape
{
protected:
double radius;
public:
Circle(double x, double y, double r) : Shape(x, y)
{
radius = r;
}
double area()const
{
return 3.14 * radius * radius;
}
};
class Rectangle : public Shape
{
protected:
double x2Coord, y2Coord;
public:
Rectangle(double x1, double y1, double x2, double y2) : Shape(x1, y1)
{
x2Coord = x2;
y2Coord = y2;
}
double area()const;
};
double Rectangle::area()const
{
return abs((xCoord - x2Coord) * (yCoord - y2Coord));
}
void fun(const Shape& sp)
{
cout << sp.area() << endl;
}
int main()
{
fun(Circle(2, 5, 4));
fun(Rectangle(2, 4, 1, 2));
return 0;
}
补充:软件开发 , C++ ,