一、编译多态(静态绑定)
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
如果在函数中用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;
}
运行结果:
计算矩形面积
调用图形类析构函数
#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.
[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.
[11]C++继承//多态. http://blog.csdn.net/pearl333/article/details/8056916.
[12] C++ 虚函数表解析. http://blog.csdn.net/haoel/article/details/1948051.
注:为了便于自己学习,无心侵权,尽可能。将所引用的文章列举出来;有些文章的内容可能会与原作重复度较高,还请谅解。如作者举报,愿意删除此文。