`
java-mans
  • 浏览: 11427472 次
文章分类
社区版块
存档分类
最新评论

C++学习之多态

 
阅读更多

C++的类机制中有支持多态的技术来解决抽象编程,它用的是一种滞后捆绑技术,
这种技术,通过预先设定其成员函数的虚函数性质,使得任何捆绑该成员函数的未定类型的对象操作在编译时,都以一个不确定的指针特殊地“引命代发”来编码,
到了运行时,遇到确定类型的对象,才突然制定其真正的行为。即滞后到运行时,根据具体类型的对象来捆绑成员函数,这样,辨别对象类型的工作就可以不用用户做了。

虚函数(Virtual Function)
1.多态条件(Polymorphism Condition)
使用类编程中,要能进行抽象编程,不随类的改动而改动,类机制必须解决这个问题,在C++中,就是虚函数机制。基类与派生类的同名操作。只要标记上virtual,则该操作便具有多态性。
如下代码所示:

#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;
}

代码输出如下:

In Base class
In Sub class


上述代码中fun是Base类的虚函数,一旦标记了基类的函数为虚函数,则后面继承类中一切同名成员函数都编程了虚函数,在test函数中,b是Base类的引用性形参,Base类对象和Sub类对象都可以作为实参传给形参b。

如果函数参数是实际复制动作的传递,则子类对象完全变成基类对象了,这样,便不会有多态了。如将上述代码中的test函数参数改为如下形式时,

如下代码所示:

void test(Base b)
{
	b.fun();
}

int main()
{
	Base bc;
	Sub sc;
	test(bc);
	test(sc);

	return 0;
}


其输出则变为:

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就能使子类的响应同名函数虚拟化。

#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;
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics