C++ 编译时多态和运行时多态

前言
    多态多为C++的三大特性之一,我们对此的了解和应用大多停留在类继承层次和运行时阶段。那既然有运行(动态)时阶段,那是否也有静态的多态?有,那就是编译时多态

正文
  动态多态

    运行时的多态存在于继承类中,通过虚函数实现动态选择调用。简单的说就是通过一张虚函数表——vptable,vptable中记录了基类的虚函数地址,在派生类中继承了基类的这张vptable,而且在派生类的构造函数中对继承来的vptable相关地址进行替换,因此在调用时通过vptable的实际地址能够知道调用哪个函数。下面是个简单的范例:

#pragma once
 
#include 
class CBase
{
public:
	CBase(){std::cout<<"CBase::CBase"<b?a:b;
	}
};
 
class CChild : public CBase
{
public:
	CChild(){std::cout<<"CChild::CChild"<b?a:b;
	}
};
 
void main()
{
	CBase *pBase = new CBase;	
	CChild *pChld = new CChild;
	pBase->getMax(5, 2);
	pBase = new CChild;
	pBase->getMax(5,2);
	getchar();
	return;
}

输出如下:

C++ 编译时多态和运行时多态_第1张图片

 

总之动态多态发生在继承关系的类中,通过虚函数表实现。那静态多态呢?

  静态多态

    静态多态是发生在编译时期的,通过模板和函数重载实现,相比动态多态不需派生关系。下面看一个范例

class Animal
{
public :
    void shout() { cout << "发出动物的叫声" << endl; };
};
class Dog
{
public:
     void shout(){ cout << "汪汪!"<
void  animalShout(T & t)
{
    t.shout();
}
int main()
{
    Animal anim;
    Dog dog;
    Cat cat;
    Bird bird;
 
    animalShout(anim);
    animalShout(dog);
    animalShout(cat);
    animalShout(bird);
 
    getchar();
}

上例就是通过模板实现静态多态,重载范例就不展示了。那么这两者区别在于什么?

 

编译时多态和运行时多态区别:

1、运行时体现了面向对象的思想,但是虚函数表增加了内存开销

2、运行时多态发生在运行时期,所以编译器无法进行优化处理

3、编译时多态运用泛型编程,在编译器完成提升运行期效率,但是无法实现模板的分离编译所以对于大工程而言编译耗时

4、编译时多态无法处理异质对象集合(什么是异质对象?)

 

延申拓展:显示接口和隐士接口

    显示接口就是指能够明确来源的接口,比如在动态多态的范例中,当调用getMax时,我们能够知道这个getMax到底是CBase的还是CChild的

    隐式接口就是指那些无法确定的来源的接口,如对于函数重载和模板,我们也不知道调用的是哪个实现。

 

解答:

    异质类:就是(存储、指向)类型不一致的数据对象,如pBase,或Template,所以异质类的实现核心就是多态+模板编程
 

你可能感兴趣的:(初学C++)