C++多态 虚(纯虚)函数 绑定详解及实例分析

多态的概念

C++多态即为:多态即为多种形式或形态,在编程语言中描述为同一种操作,可以有多种实现形式

C++中多态产生的必要条件

1、继承

2、要求有虚函数

3、要求有父类指针或引用指向派生类的对象

虚函数、纯虚函数

C++为实现多态引入虚函数、纯虚函数的概念!

虚函数:在类的函数前边加上 virtual 即可,这样这个函数就变为你想要override的函数!当你引用基类的指针或引用指向一个继承类的对象的时候,你调用一个虚函数,如果在子类重载了这个函数,你便是调用了子类中 这个函数的版本!

说明:对于基类中加virtual的函数,其所有的派生类中都不需要在加virtual,系统默认该函数就是虚函数,不用在显示的在函数前面在virtual。

纯虚函数:纯虚函数的定义 为虚函数 = 0 ;形如: virtual void shout() = 0 ;在虚函数后边加  =0;

说明:1、含有纯虚函数的类是抽象类,不可以实例化。

           2、纯虚函数在基类中定义,在子类的实现,(子类中必须实现)。

如下代码:

#include <iostream>

using namespace std;

class Base
{

public:
    Base()
    {
        cout<<"Base construct"<<endl;
        foo();
    }
    virtual void foo()
    {
        cout<<"Base foo"<<endl;
    }
    virtual void fun1() = 0;
    virtual ~Base()
    {
        cout<<"Base destruct"<<endl;
    }
};

class Drive:public Base
{
public:
    Drive()
    {
        cout<<"Drive construct"<<endl;
        foo();
    }
    void foo()
    {
        cout<<"Drive foo"<<endl;
    }
    void fun1()
    {
        cout<<"fun1 instantiated"<<endl;
    }
    ~Drive()
    {
        cout<<"Drive destruct"<<endl;
    }
};

int main()
{
    Base *ba = new Drive();
    delete ba;
    return 0;
}

说明:

1、对于纯虚函数  virtual void fun1() = 0; 假如说派生类中不对其实现,则不能编译通过。

2、含有虚函数的类的析构函数一般要 设置为 虚析构 函数,这样保证可以调用子类中的 析构函数。

3、抽象类不可以实例化 ,例如: Base *ba = new Base(); 不可以被编译通过。

4、C++的多态就是同一种操作,可以产生不同的形态。


在函数名前边 加入 virtual ,此函数就变为一个虚函数,虚函数的特点是,可以实现“动态联编”,它可以在运行时判断所指向的对象,并自动调用相应的函数!

对于虚函数与纯虚函数的区别:

首先:强调一个概念 
定义一个函数为虚函数,不代表函数为不被实现的函数 
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数 
定义一个函数为纯虚函数,才代表函数没有被实现 
定义他是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
 

对继承的影响: 
普通的类(没有虚函数,纯虚函数)就可以被继承,而且工作的相当好 ,但是不能实现多态!

为什么要定义纯虚函数?

可以从两个方面考虑:

1.为了安全.因为避免任何需要明确但是因为不小心而导致的未知的结果. 提醒子类去做应做的实现。
2.为了效率,不是程序执行的效率,而是为了编码的效率。

binding

这里介绍下 动态binding  静态 binding 

C++中支持两种多态:

1、编译时多态:函数运行前已经发生过的事件        函数重载、运算符重载(overload)等              静态binding

2、运行时多态:函数运行时发生的事件                  虚函数机制                                  动态binding

函数banding

1、binding(绑定)  : 函数调用函数体连接起来叫做绑定

2、预绑定(静态绑定)在程序运行之前执行,由编译器与链接器执行,编译时绑定

3、后绑定(动态绑定):   编译器在编译时未确定要调用那个函数,必须通过函数运行时所产生的信息来通知确定要调用那个函数;(动态绑定)  ;运行时绑定


静态绑定与动态绑定的区别:

预绑定:

         1、意味着绑定基于的信息都是静态的, 是编译和连接时就可以确定的
         2、编译系统根据指针(或引用)本身的类型,而不是它所指向的对象的类型来进行绑定;
         3、预绑定的实体包括一般函数、重载函数、非虚成员函数和非虚友元函数
后绑定:
          1、在运行时,根据对象类型的不同来选择合适的函数调用,这些类型信息在编译时是不可知的,故只能用后绑定解决这一问题;
         2、拥有虚函数的类对象中,必然包含着相应的类型信息,否则动态绑定不可能实现;
         3、编译时的多态的实现,取决于程序的静态信息是否足够为相同的程序实体确定不同的标识符。这里的程序实体,是指程序代码中的各种名称和代码段;
         4、要实现运行时的多态,进行动态联编,就必须使用虚函数

编译时多态(运行前多态,静态绑定) ,表现在以下几个方面:

    1、对于在一个类中说明的重载(overload),编译系统根据重载函数的参数的个数、参数类型、参数的顺序的差别,来分别调用相应的函数。

    2、对于基类和派生类中的重载函数,即时所带的参数完全相同,但由于他们属于不同的类,在编译时根据对象名前缀来加以区别,或者使用"类名:: ",也可以指示出编译器调用那个成员函数。

    3、调用编译时多态时,优点在于高效率,因为编译系统可以在运行前对代码进行优化;缺点在与缺少灵活性,不足以满足程序对扩展性的要求

例1:编写 基类、派生类、派生类的派生类,在基类中定义虚函数,并全部实现,为每个类定义对象,观察每个对象的大小及内存的分配规律:

#include <iostream>
using namespace std;

//基类
class Base
{
    //变量的权限问题,默认情况下是 类的 私有变量
    int x;
public:
    Base(){cout<<"default construct Base\n";}
    Base(int n):x(n){ cout<<"construct Base\n"; }
    ~Base(){ cout<<"destructor Base\n"; }
    virtual void setx(int n) {this->x = n; cout<<"in Base::setx\n";}
    virtual int getx() { cout<<"in Base::getx\n";return this->x; }
} ;

//基类
class Derive:public Base
{
    int x;
public:
    Derive(){ cout<<"default construct Derive\n"; }
    Derive(int x1,int x2):Base(x1),x(x2){ cout<<"construct Derive\n"; }
    ~Derive(){ cout<<"destructor Derive\n"; }
    void setx(int n) {this->x = n; cout<<"in Derive::setx\n"; }
    int getx()  { cout<<"in Derive::getx\n"; return this->x; }
};
class subDerive : public Derive
{
    int x;
    public:
    subDerive(){ cout<<"default construct subDerive\n"; }
    subDerive(int n1,int n2,int n3):Derive(n1,n2),x(n3){ cout<<"construct subDerive\n"; }
    ~subDerive(){ cout<<"destructor subDerive\n"; }
    void setx(int n) {this->x = n ; cout<<"in subDerive::setx\n"; }
    int getx()  { cout<<"in subDerive::getx\n"; return this->x;}
};

int main()
{
    cout<<"sizeof Base : "<<sizeof(Base)<<endl;
    cout<<"sizeof Derive : "<<sizeof(Derive)<<endl;
    cout<<"sizeof SubDerive : "<<sizeof(subDerive)<<endl<<endl;

    Base base(1);
    Derive derive(2,3);
    subDerive subder(4,5,6);

    cout<<endl<<endl;

    return 0;
}

运行结果:



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值