美文网首页
C++编译期多态和运行期多态

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

作者: 曹志文 | 来源:发表于2018-06-15 09:42 被阅读0次

C++多态有多种实现方式,在面对对象编程时,采用的是运行期多态,也称动态多态。在泛型编程中,多态基于模板的具现化与函数的重载解析,这种多态在编译期进行,也称编译器多态或者静态多态。

运行期多态

运行期多态归根结底就是类继承的一个特性。我们习惯于抽象出不同功能的对象的共有功能集合,在基类中将这些共有功能声明为虚函数(也称虚接口),然后由子类去重写这些虚函数,以实现多态。


class Animal
{
public :
    void Animal();
    virtual void shout() = 0;
};

void Animal::Animal()
{
    std::cout << "Constructor of Animal" << std::endl;
}

class Dog :public Animal
{
public:
    void Dog();
    virtual void shout(){ cout << "汪汪!"<<endl; }
};

void Dog::Dog()
{
    std::cout << "Constructor of Dog" << std::endl;
}

class Cat :public Animal
{
public:
    virtual void shout(){ cout << "喵喵~"<<endl; }
};

class Bird : public Animal
{
public:
    virtual void shout(){ cout << "叽喳!"<<endl; }
};

int main()
{
    Animal * anim1 = new Dog;
    Animal * anim2 = new Cat;
    Animal * anim3 = new Bird;
     
    //指针的类型都是基类,通过指针(或引用)调用的接口,
    //在运行期确定指针(或引用)所指对象的真正类型,调用该类型对应的接口
    anim1->shout();
    anim2->shout();
    anim3->shout();
 
    //delete 对象
    delete anim1;
    delete anim2;
    delete anim3;
    return 0;
}

当某个类声明了虚函数时,编译器为该对象安插一个虚函数表指针,并且为该类对象安插一个虚函数表指针,并且为该类设置一个唯一的虚函数表

如果一个类有一个或者多个成员函数是虚函数,编译器就为这个类创建一个虚函数表。这个表为每一个虚成员函数记录一个指针(内存地址)。指针指向相应成员函数代码的入口地址。如果一个虚函数被继承下来,并且没有改变,那么虚函数表中相应项指向的就是这个函数在父类(或者其他祖先类)的定义。如果一个虚函数有新的定义,那么表中这个虚函数的指针就会指向新的定义。记住,虚函数的属性是会继承的,一旦一个类有一个虚函数表,那么所有它的子孙类也会有一个虚函数表。
一旦我们创建了一个包含虚函数的类的对象,那么C++运行时系统就会自动增加另外一个指针类描述这个存储在内存中的对象。这个指针指向类的虚函数表。当我们使用一个指向该对象的指针来调用成员函数时,运行时系统会使用虚函数表来确定调用哪一个版本的成员函数,而不是根据这个指针的类型。

编译期多态

对于模板参数而言,多态是通过模板具现化和函数重载解析实现的。不同的模板参数调用不同的函数,这就是编译期多态。

class Animal
{
public :
    void shout() { cout << "发出动物的叫声" << endl; };
};
class Dog
{
public:
     void shout(){ cout << "汪汪!"<<endl; }
};
class Cat
{
public:
     void shout(){ cout << "喵喵~"<<endl; }
};
class Bird
{
public:
     void shout(){ cout << "叽喳!"<<endl; }
};
template <typename T>
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();
}

在编译之前,函数模板中t.shout()调用的是哪个接口并不确定。在编译期间,编译器推断出模板参数,因此确定调用的shout是哪个具体类型的接口。不同的推断结果调用不同的函数,这就是编译器多态。这类似于重载函数在编译器进行推导,以确定哪一个函数被调用。

总结

静态绑定和动态绑定都是用父类指向子类。区别就是有无虚函数。
如果没有虚函数就是静态绑定,生成一个子类对象,但是当调用函数的时候,是根据指针类型判断,所以仍然会调用父类的函数。
而动态绑定会查询虚函数表,从而调用子类函数。

相关文章

  • C++编译期多态和运行期多态

    C++多态有多种实现方式,在面对对象编程时,采用的是运行期多态,也称动态多态。在泛型编程中,多态基于模板的具现化与...

  • C++ 的多态(Polymorphism), virtual f

    多态 c++支持两种多态,编译时多态和运行时多态但其实编译时多态根本不是真正的多态,编译时多态就是函数的重载,ov...

  • C++第六篇多态

    C++中的多态性分为编译时多态性和运行时多态性,编译时多态通过函数重载和模板体现,运行多态通过虚函数体现编译、连接...

  • 【Effective C++(7)】模板与泛型编程

    41 了解隐式接口和编译期多态 OOP总是通过显式接口和运行期多态解决问题,如函数doProcessing内的w类...

  • C++基础多态(PolyMorphism)

    C++按照实现的时机分为编译时多态和运行时多态1.编译时多态也成为静态连编,是指程序在编译的时候就确定了多态性,通...

  • java多态面试题

    java多态性 多态分两种: (1) 编译时多态(设计时多态):方法重载。 (2) 运行时多态:JAVA运...

  • 六、多态与虚函数

    多态的基本概念 多态 多态分为编译时多态和运行时多态。 编译时多态主要是指函数的重载(包括运算符的重载)。对重载函...

  • c++多态

    什么是多态性? 多态:相同对象收到不同消息或不同对象收到相同消息时产生不同的动作。C++支持两种多态性:编译时多态...

  • 深刻剖析之c++博客文章

    三大特性 封装、继承、多态 多态 C++ 虚函数表解析C++多态的实现原理 介绍了类的多态(虚函数和动态/迟绑定)...

  • 查漏补缺

    C++虚函数: 多态: 静态多态(重载)、动态多态(虚函数) 虚函数 虚函数表:编译器为每个类创建了一个虚函数表...

网友评论

      本文标题:C++编译期多态和运行期多态

      本文链接:https://www.haomeiwen.com/subject/aqfpeftx.html