虚函数学习笔记

 虚函数学习笔记

      C++中的虚函数的作用主要是实现了多态的①机制。虚函数必须是基类的非静态成员函数,其访问权限可以是protectedpublic,在基类的类定义中定义虚函数的一般形式:virtual 函数返回值类型 虚函数名(形参表)

                                             { 函数体 }

      虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。

      当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。

      动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数。

                                          格式:

                                     1、指向基类的指针变量名->虚函数名(实参表)

                                         2、基类对象的引用名. 虚函数名(实参表)

举例:

#include<iostream.h>

  class Cshape

{

public:

void SetColor( int color) { m_nColor=color;}

      virtual void Display( void) { cout<<"Cshape"<<endl; }

  private:

      int m_nColor;

  };

  class Crectangle: public Cshape

  {

  public:

      virtual void Display( void) { cout<<"Crectangle"<<endl; }

  };

  class Ctriangle: public Cshape

  {

public

virtual void Display( void) { cout<<"Ctiangle"<<endl; }

  };

  class Cellipse :public Cshape

  {

public:

virtual void Display(void) { cout<<"Cellipse"<<endl;}

  };

  void main()

  {

      Cshape obshape;

      Cellipse obEllipse;

      Ctriangle obTriangle;

      Csquare obSquare;

      Cshape * pShape[4]= { &obShape, &obEllipse,&obTriangle, & obSquare };

    for( int I= 0; I< 4; I++)

          pShape[I]->Display( );

  }

  本程序运行结果:

  Cshape

  Cellipse

  Ctriangle

      Csquare

所以,实现动态联编需要三个条件:

  1、 必须把动态联编的行为定义为的虚函数。

  2、 类之间存在子类型关系,一般表现为一个类从另一个类公有派生而来。

      3、 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。

定义虚函数的限制:
  (1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。

  (2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”

  (3)当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数自动成为虚函数。

      (4如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类的派生类中,也不能出现这种同名函数。

虚函数的实现主要是通过虚函数表(Virtual Table),简称V-table。

几个易混淆概念的区分

虚基类

从代码中可以看出类B C都继承了类AiValue成员,因此类B C都有一个成员变量iValue ,而类D又继承了B C,这样类D就有一个重名的成员 iValue(一个是从类B中继承过来的,一个是从类C中继承过来的).在主函数中调用d.iValue 因为类D有一个重名的成员iValue编译器不知道调用 从谁继承过来的iValue所以就产生的二义性的问题.正确的做法应该是加上作用域限定符 d.B::iValue 表示调用从B类继承过来的iValue。不过 D的实例中就有多个iValue的实例,就会占用内存空间。所以C++中就引用了虚基类的概念,来解决这个问题。

在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例。例如iValue这个成员,从类 D这个角度上来看,它是从类B与类C继承过来的,而类B C又是从类A继承过来的,但它们只保留一个副本。因此在主函数中调用d.iValue时就不 会产生错误。


纯虚函数:

与其叫纯虚函数还不如叫抽象类,它只是声明一个函数但不实现它,让派生类去实现它,其实这也很好理解。

声明方式:virtual void funtion()=0

引入原因:

1、为了方便使用多态特性,我们常常需要在基类中定义虚函数。

2、但在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数,则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

 

 

 

 

 

 

 

纯虚函数不能实化化,但可以声明指针。纯虚函数的作用是为派生类提供一个一致的接口。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`sigprocmask()` 函数是用于修改进程的信号屏蔽字的函数,它可以阻塞或允许特定的信号。下面是关于 `sigprocmask()` 函数的一些学习笔记: 1. `sigprocmask()` 函数的头文件为 `<signal.h>`。 2. `sigprocmask()` 函数的原型为: ``` int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); ``` - `how` 表示如何修改信号屏蔽字,有三个取值:`SIG_BLOCK`、`SIG_UNBLOCK` 和 `SIG_SETMASK`。分别表示阻塞、解除阻塞和设置信号屏蔽字。 - `set` 表示要修改的信号集合。 - `oldset` 表示原来的信号集合。 3. `sigprocmask()` 函数可以修改进程的信号屏蔽字,控制是否允许或阻塞某些信号的处理。 4. 信号屏蔽字是一个二进制位向量,每个位代表一个信号,如果该位为 1,则表示该信号被屏蔽,不会被处理;如果该位为 0,则表示该信号是允许的,可以被处理。 5. `sigprocmask()` 函数可以使用 `sigemptyset()`、`sigfillset()`、`sigaddset()`、`sigdelset()` 等函数来创建和修改信号集合。 6. `sigprocmask()` 函数可以用于防止信号的竞争条件,例如在多线程程序使用信号处理函数时,可以使用信号屏蔽字来防止多个线程同时处理同一个信号。 7. `sigprocmask()` 函数还可以用于实现临界区保护,即在进入临界区时,屏蔽某些信号,以防止信号处理函数断临界区代码的执行。 总之,`sigprocmask()` 函数是一个常重要且常用的函数,可以用于控制信号的处理,保护临界区等。在学习和使用该函数时,需要注意其参数的含义和使用方法,以及信号屏蔽字的概念和使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值