C++多态性

C++多态性
多态性是指向不同的对象发送同一个消息,不同对象对同一消息产生不同行为。即“一个接口,多种方法”。


一、编译多态(静态绑定

1)函数模板

eg:

#include <iostream>

using std::cout;
using std::endl;

template <typename T>
T max(const T& lsh, const T& rhs)
{
	return (lsh >= rhs) ? lsh : rhs;
}

int main(int argc, char* argv[])
{
	int a = 3;
	int b = 4;
	cout << max(a, b) << endl;s

	float c = 2.4;
	float d = 1.2;
	cout << max(c, d) << endl;

	return 0;
}
运行结果:
4
2.4


2)函数重载
函数名相同,但函数参数类型不同,参数个数不同或两者皆有。

eg:

#include <iostream>

using std::cout;
using std::endl;

int max(int a, int b)
{
	return (a > b) ? a : b;
}

int max(int a, int b, int c)
{
	return max(max(a, b), c);
}

int main(int argc, char* argv[])
{
	int a = 3;
	int b = 4;
	int c = 5;
	cout << max(a, b) << endl;
	cout << max(a, b, c) << endl;

	return 0;
}

运行结果:

4

5


3)运算符重载

eg:

#include <iostream>

using std::cout;
using std::endl;

class A {
public:
	A(int data) : data(data) {};

	void show() {
		cout << "data = " << data << endl;
	} 

	A operator+(const A& a) {
		return A(data + a.data);
	}

private:
	int data;
};

int main(int argc, char *argv[])
{
	A a1(100), a2(200);
	(a1 + a2).show();
	return 0;
}
运行结果:
data = 300


二、运行多态(动态绑定)
1)虚函数
虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖,或者称为重写。
一个派生类用基类的指针表示,派生类和基类中有相同的函数名,相同的参数及相同的返回值。当用基类指针指向这些派生类对象时,系统会自动用派生类中的同名函数来代替基类中的虚函数。
只有类的成员函数才能声明为虚函数,全局函数及静态成员函数不能声明为虚函数。
虚函数声明格式:

virtual 返回类型 函数名(形参表)
{
函数体
}
eg:

#include <iostream>

using std::cout;
using std::endl;

class Polygon
{
protected:
	int width, height;
public:
	void set_values(int a, int b)
	{
		width = a; height = b;
	}
	virtual int area()
	{
		return 0;
	}
};

class Rectangle : public Polygon {
public:
	int area()
	{
		return width * height;
	}
};

class Triangle : public Polygon {
public:
	int area()
	{
		return (width * height / 2);
	}
};

int main(int argc, char* argv[]) 
{
	Rectangle rect;
	Triangle trgl;
	Polygon poly;
	Polygon * ppoly1 = ▭
	Polygon * ppoly2 = &trgl;
	Polygon * ppoly3 = &poly;
	ppoly1->set_values(4, 5);
	ppoly2->set_values(4, 5);
	ppoly3->set_values(4, 5);
	cout << ppoly1->area() << '\n';
	cout << ppoly2->area() << '\n';
	cout << ppoly3->area() << '\n';
	return 0;
}

运行结果:

20

10

0


2)虚析构函数
如果在函数中用new建立一个派生类对象和定义一个基类对象指针,并将派生类对象的地址赋给基类对象指针时。当用delete运算符来撤销无名对象时,系统只执行基类析构函数,而不执行派生类析构函数。
如果要调用派生类的析构函数,则必须在基类的析构函数前加上virtual。
虚析构函数声明格式:
virtual ~类名()
{
函数体
}
eg1:
#include <iostream>

using std::cout;
using std::endl;

class Graph
{
protected:
	double x;
	double y;
public:
	Graph(double x, double y);
	virtual void showArea();
	~Graph();
};

Graph::Graph(double x, double y)
{
	this->x = x;
	this->y = y;
}

void Graph::showArea()
{
	cout << "计算图形面积" << endl;
}

Graph::~Graph()
{
	cout << "调用图形类析构函数" << endl;
}

class Rectangle :public Graph
{
public:
	Rectangle(double x, double y) :Graph(x, y) {};
	void showArea();
	~Rectangle();
};

void Rectangle::showArea()
{
	cout << "计算矩形面积" << endl;
}

Rectangle::~Rectangle()
{
	cout << "调用矩形类析构函数" << endl;
}

int main(int argc, char* argv[])
{
	Graph *graph;
	graph = new Rectangle(10, 5);
	graph->showArea();
	delete graph;
	return 0;
}

运行结果:

计算矩形面积

调用图形类析构函数


eg2:

#include <iostream>

using std::cout;
using std::endl;

class Graph
{
protected:
	double x;
	double y;
public:
	Graph(double x, double y);
	virtual void showArea();
	virtual ~Graph();
};

Graph::Graph(double x, double y)
{
	this->x = x;
	this->y = y;
}

void Graph::showArea()
{
	cout << "计算图形面积" << endl;
}

Graph::~Graph()
{
	cout << "调用图形类析构函数" << endl;
}

class Rectangle :public Graph
{
public:
	Rectangle(double x, double y) :Graph(x, y) {};
	void showArea();
	~Rectangle();
};

void Rectangle::showArea()
{
	cout << "计算矩形面积" << endl;
}

Rectangle::~Rectangle()
{
	cout << "调用矩形类析构函数" << endl;
}

int main(int argc, char* argv[])
{
	Graph *graph;
	graph = new Rectangle(10, 5);
	graph->showArea();
	delete graph;
	return 0;
}
运行结果:
计算矩形面积
调用矩形类析构函数
调用图形类析构函数


3)纯虚函数

在基类中只声明虚函数而不给出具体的函数定义体,将它的具体定义放在各派生类中。通过该基类的指针或引用就可以调用所有派生类的虚函数,基类只是用于继承,仅作为一个接口,具体功能在派生类中实现。

纯虚函数格式:

virtual返回类型 函数名(形参表)=0;

如果一个类中至少有一个纯虚函数,那么就称该类为抽象类。对于抽象类有以下几个注意点:

(1)抽象类只能作为其他类的基类来使用,不能建立抽象类对象;
(2) 不允许从具体类中派生出抽象类(不包含纯虚函数的普通类);

(3)抽象类不能用作函数的参数类型、返回类型和显示转化类型;

(4)如果派生类中没有定义纯虚函数的实现,而只是继承成了基类的纯虚函数。那么该派生类仍然为抽象类。一旦给出了对基类中虚函数的实现,那么派生类就不是抽象类了,而是可以建立对象的具体类。

eg:

#include <iostream>

using std::cout;
using std::endl;

class Polygon
{
protected:
	int width, height;
public:
	void set_values(int a, int b)
	{
		width = a; height = b;
	}
	virtual int area(void) = 0;
};

class Rectangle : public Polygon
{
public:
	int area(void)
	{
		return (width * height);
	}
};

class Triangle : public Polygon 
{
public:
	int area(void)
	{
		return (width * height / 2);
	}
};

int main(int argc, char* argv[]) 
{
	Rectangle rect;
	Triangle trgl;
	Polygon * ppoly1 = ▭
	Polygon * ppoly2 = &trgl;
	ppoly1->set_values(4, 5);
	ppoly2->set_values(4, 5);
	cout << ppoly1->area() << '\n';
	cout << ppoly2->area() << '\n';
	return 0;
}
运算结果:
20
10


4)虚表
虚函数通过一张虚函数表来实现的。此表为类的虚函数的地址表,通过此表解决继承、覆盖的问题,保证其真实反应实际的函数。为了保证取到虚函数表的最高的性能,编译器将虚函数表的指针存在于对象实例中最前面的位置。通过该对象实例的地址得到此虚函数表,然后遍历函数指针,从而调用相应的函数。

(1)一般继承(无虚函数覆盖)
a、虚函数按照其声明顺序放于表中
b、父类的虚函数在子类的虚函数前面
eg:

#include <iostream>

using std::cout;
using std::endl;

typedef void(*Fun)(void);

class Base
{
public:
	virtual void f() {
		cout << "Base::f()" << endl;
	}
	virtual void g() {
		cout << "Base::g()" << endl;
	}
	virtual void h() {
		cout << "Base::h()" << endl;
	}
};

class Derive :public Base
{
public:
	virtual void f1() {
		cout << "Derive::f1()" << endl;
	}
	virtual void g1() {
		cout << "Derive::g1()" << endl;
	}
	virtual void h1() {
		cout << "Derive::h1()" << endl;
	}
};

int main(int argc, char* argv[])
{
	Derive b;
	Fun pFun = NULL;

	cout << "对象地址:" << (int*)(&b) << endl;
	cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl;

	pFun = (Fun)*((int*)*(int*)(&b));
	cout << pFun << endl;  // Base::f()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 1);
	cout << pFun << endl; // Base::g()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 2);
	cout << pFun << endl; // Base::h()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 3);
	cout << pFun << endl; // Derive::f1()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 4);
	cout << pFun << endl; // Derive::g1()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 5);
	cout << pFun << endl; // Derive::h1()
	pFun();

	return 0;
}

其运行结果:

对象地址: 0041FAE0

虚函数表地址: 01149B6C

01141087

Base::f()

01141203

Base::g()

011410CD

Base::h()

0114102D

Derive::f1()

011413DE

Derive::g1()

01141334

Derive::h1()

其继承关系:

其内存地址:

其虚函数表:

注:在上图中,虚函数表最后的一个结点是虚函数表的结束结点,类似于字符串的结束符“/0”。此标志的值在不同的编译器下是不同的,在Win7+VS2015下,此值为NULL;而在Ubuntu14+GCC下,此值如果为1,表示还有下一个虚函数表;如果为0,表示这是最后一个虚函数表。


(2)一般继承(有虚函数覆盖)

a、覆盖的函数被放到虚表中原来父类虚函数的位置

b、没有被覆盖的函数依旧

eg:

#include <iostream>

using std::cout;
using std::endl;

typedef void(*Fun)(void);

class Base
{
public:
	virtual void f() {
		cout << "Base::f()" << endl;
	}
	virtual void g() {
		cout << "Base::g()" << endl;
	}
	virtual void h() {
		cout << "Base::h()" << endl;
	}
};

class Derive :public Base
{
public:
	void f() {
		cout << "Derive::f()" << endl;
	}
	virtual void g1() {
		cout << "Derive::g1()" << endl;
	}
	virtual void h1() {
		cout << "Derive::h1()" << endl;
	}
};

int main(int argc, char* argv[])
{
	Derive b;
	Fun pFun = NULL;

	cout << "对象地址:" << (int*)(&b) << endl;
	cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl;

	pFun = (Fun)*((int*)*(int*)(&b));
	cout << pFun << endl;  // Base::f()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 1);
	cout << pFun << endl; // Base::g()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 2);
	cout << pFun << endl; // Base::h()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 3);
	cout << pFun << endl; // Derive::f1()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 4);
	cout << pFun << endl; // Derive::g1()
	pFun();

	return 0;
}
其运行结果:
对象地址: 001AF7E8
虚函数表地址: 00D49B6C
00D41343
Derive::f()
00D411FE
Base::g()
00D410C8
Base::h()
00D413DE
Derive::g1()
00D4132F
Derive::h1()
其继承关系:


其内存地址:

其虚函数表:


(3)多重继承(无虚函数覆盖)

a、每个父类都有自己的虚表

b、子类的成员函数被被覆盖的放到父类

eg:

#include <iostream>

using std::cout;
using std::endl;

typedef void(*Fun)(void);

class Base1
{
public:
	virtual void f() {
		cout << "Base1::f()" << endl;
	}
	virtual void g() {
		cout << "Base1::g()" << endl;
	}
	virtual void h() {
		cout << "Base1::h()" << endl;
	}
};

class Base2
{
public:
	virtual void f() {
		cout << "Base2::f()" << endl;
	}
	virtual void g() {
		cout << "Base2::g()" << endl;
	}
	virtual void h() {
		cout << "Base2::h()" << endl;
	}
};

class Base3
{
public:
	virtual void f() {
		cout << "Base3::f()" << endl;
	}
	virtual void g() {
		cout << "Base3::g()" << endl;
	}
	virtual void h() {
		cout << "Base3::h()" << endl;
	}
};

class Derive :public Base1, public Base2, public Base3
{
public:
	virtual void f1() {
		cout << "Derive::f1()" << endl;
	}
	virtual void g1() {
		cout << "Derive::g1()" << endl;
	}
	virtual void h1() {
		cout << "Derive::h1()" << endl;
	}
};

int main(int argc, char* argv[])
{
	Derive b;
	Fun pFun = NULL;

	cout << "对象地址:" << (int*)(&b) << endl;
	cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl;

	pFun = (Fun)*((int*)*(int*)(&b));
	cout << pFun << endl;  // Base1::f()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 1);
	cout << pFun << endl; // Base1::g()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 2);
	cout << pFun << endl; // Base1::h()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 3);
	cout << pFun << endl; // Derive::f1()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 4);
	cout << pFun << endl; // Derive::g1()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 5);
	cout << pFun << endl; // Derive::h1()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b)+ 1));
	cout << pFun << endl; // Base2::f()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 1) + 1);
	cout << pFun << endl; // Base2::g()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 1) + 2);
	cout << pFun << endl; // Base2::h()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 2));
	cout << pFun << endl; // Base3::f()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 2) + 1);
	cout << pFun << endl; // Base3::g()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 2) + 2);
	cout << pFun << endl; // Base3::h()
	pFun();

	return 0;
}
其运行结果:
对象地址:0036FCE4
虚函数表地址: 010E9C00
010E1339
Base1::f()
010E125D
Base1::g()
010E12CB
Base1::h()
010E1032
Derive::f1()
010E1406
Derive::g1()
010E1352
Derive::h1()
010E1005
Base2::f()
010E115E
Base2::g()
010E13ED
Base2::h()
010E10E1
Base3::f()
010E1037
Base3::g()
010E105A
Base3::h()


其继承关系:


其内存地址:

其虚函数表:



(4) 多重继承(有虚函数覆盖)

a、每个父类都有自己的虚表

b、子类的成员函数被放到虚表中原来父类虚函数的位置

c、没有被覆盖的依旧

eg:

#include <iostream>

using std::cout;
using std::endl;

typedef void(*Fun)(void);

class Base1
{
public:
	virtual void f() {
		cout << "Base1::f()" << endl;
	}
	virtual void g() {
		cout << "Base1::g()" << endl;
	}
	virtual void h() {
		cout << "Base1::h()" << endl;
	}
};

class Base2
{
public:
	virtual void f() {
		cout << "Base2::f()" << endl;
	}
	virtual void g() {
		cout << "Base2::g()" << endl;
	}
	virtual void h() {
		cout << "Base2::h()" << endl;
	}
};

class Base3
{
public:
	virtual void f() {
		cout << "Base3::f()" << endl;
	}
	virtual void g() {
		cout << "Base3::g()" << endl;
	}
	virtual void h() {
		cout << "Base3::h()" << endl;
	}
};

class Derive :public Base1, public Base2, public Base3
{
public:
	void f() {
		cout << "Derive::f()" << endl;
	}
	virtual void g1() {
		cout << "Derive::g1()" << endl;
	}
	virtual void h1() {
		cout << "Derive::h1()" << endl;
	}
};

int main(int argc, char* argv[])
{
	Derive b;
	Fun pFun = NULL;

	cout << "对象地址:" << (int*)(&b) << endl;
	cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl;

	pFun = (Fun)*((int*)*(int*)(&b));
	cout << pFun << endl;  // Derive::f()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 1);
	cout << pFun << endl; // Base1::g()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 2);
	cout << pFun << endl; // Base1::h()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 3);
	cout << pFun << endl; // Derive::g1()
	pFun();

	pFun = (Fun)*((int*)*(int*)(&b) + 4);
	cout << pFun << endl; // Derive::h1()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b)+ 1));
	cout << pFun << endl; // Derive::f()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 1) + 1);
	cout << pFun << endl; // Base2::g()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 1) + 2);
	cout << pFun << endl; // Base2::h()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 2));
	cout << pFun << endl; // Derive::f()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 2) + 1);
	cout << pFun << endl; // Base3::g()
	pFun();

	pFun = (Fun)*((int*)*((int*)(&b) + 2) + 2);
	cout << pFun << endl; // Base3::h()
	pFun();

	return 0;
}
其运行结果:
对象地址: 0038F9DC
虚函数表地址: 00EC9C00
00EC136B
Derive::f()
00EC1262
Base1::g()
00EC12D0
Base1::h()
00EC1410
Derive::g1()
00EC1357
Derive::h1()
00EC11DB
Derive::f()
00EC1159
Base2::g()
00EC13F7
Base2::h()
00EC11E0
Derive::f()
00EC1032
Base3::g()
00EC1055
Base3::h()
其继承关系:

其内存地址:


其虚函数表:



参考文献

[1]C++ Virtual详解. http://www.cnblogs.com/xd502djj/archive/2010/09/22/1832912.html.

[2] 浅谈C++多态性. http://blog.csdn.net/hackbuteer1/article/details/7475622.

[3]C++之多态性与虚函数. http://www.cnblogs.com/CaiNiaoZJ/archive/2011/08/11/2134673.html.

[4]C++多态性. http://zhidao.baidu.com/link?url=pjvK5KLQzRn5N_kAJjOf9CILsQoaxXjx8oIusE1gy26F9lIsgSzwcOcRux2qhA-uGHkJUfDNwaBe9gpGIxpfYq.

[5]C++封装继承多态总结. http://blog.csdn.net/ruyue_ruyue/article/details/8211809.[6]C++多态的实现及原理详细解析. http://www.jb51.net/article/41809.htm.

[7]C++虚函数、多态性与虚表. http://my.oschina.net/hnuweiwei/blog/280894.

[8]Polymorphism. http://www.cplusplus.com/doc/tutorial/polymorphism/.

[9]Polymorphism in c++. http://stackoverflow.com/questions/5854581/polymorphism-in-c.

[10] 静多态. http://baike.baidu.com/link?url=Rjmg-K4ZCNMHSST_xCdJFhHufyChSixm1UJY4ibJHoI1PL4lhPRYnFchIyURFMFTD4wBUQonXsVWm517CaKUvq.

[11]C++继承//多态. http://blog.csdn.net/pearl333/article/details/8056916.

[12] C++ 虚函数表解析. http://blog.csdn.net/haoel/article/details/1948051.

 

注:为了便于自己学习,无心侵权,尽可能。将所引用的文章列举出来;有些文章的内容可能会与原作重复度较高,还请谅解。如作者举报,愿意删除此文。







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值