zoukankan      html  css  js  c++  java
  • C++基础(纯虚函数与抽象类)

    C++基础之纯虚函数与抽象类

    引言

      纯虚函数在C++编程中的地位很重要,其关联到了设计模式中“接口”的概念。

    语法

      纯虚函数的语法:

      1、  将成员函数声明为virtual

      2、  后面加上 = 0

      3、  该函数没有函数体

    1 class <类名>
    2 {
    3      virtual <类型><函数名>(<参数表>) = 0;
    45  };

      例如:

    1 class CmdHandler
    2 {
    3      virtual void OnCommand(char* cmdline) = 0;
    4 5  };

      在许多情况下,在基类中不能对虚函数给出有意义有实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。

    抽象类

      含有纯虚函数的类叫做抽象类(纯虚类),抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承层次结构的较上层。

      抽象类不能被实例化,即无法创建该类的对象。

      CmdHandler ch;                    // 编译错误!!

      CmdHandler *p = new CmdHandler();  // 编译错误!!

      在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限。

      抽象类的主要作用是将有关的组织在一个继承层次结构中,由它来为它们提供一个公共的根,相关的子类是从这个根派生出来的。

          抽象类刻画了一组子类的操作接口的通用语义,这些语义也传给子类。一般而言,抽象类只描述这组子类共同的操作接口,而完整的实现留给子类。

    抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了。

    接口

      实际用途:充当“接口函数”

      (相当于Java中的interface语法)

      (用于替代C中的回调函数的用法)

      接口规范:凡是遵循此规范的类,都必须实现指定的函数接口,通常是一系列接口。

      上述定义的抽象类可以理解为:凡是遵循CmdHandler规范的类,都必须实现指定的函数接口:OnCommand()。

    一个实例

      需求:用户输入一行命令,按回车完成输入。要求解析命令的输入,并处理之。

      设计

             CmdInput:用于接收用户的输入

             CmdHandler:规定一系列函数接口

         CmdParser:接口的实现,实际用于解析的处理类

         说明

                可见,CmdInput只接收输入的内容,而CmdParser用于对输入的内容进行解析,两个类各做各的,互不干涉,两者并不知道对方的存在,而是通过抽象类CmdHandler充当“接口”联系起来。

           代码

    // main.cpp
    #include “CmdInput.h”
    #include “CmdParser.h”
    int main(void)
    {
               CmdInput CInput;
               CmdParser CParser;
               CInput.SetHandler(&CParser);
               CInput.Run();
               return 0;
    }
    
     
    // CmdHandler.h
    /* CmdHandler 接口类*/
    class CmdHandler
    {
    public:
             virtual ~CmdHandler() {}                      // 析构函数声明为 virtual
             virtual void OnCommand(char* cmdline) = 0;      // 纯虚函数
    };
    
    // CmdInput.h
    #include “CmdHandler.h”
    class CmdInput
    {
    public:
               CmdInput();
               void SetHandler(CmdHandler* pCHandler);
               int Run();
    private:
               CmdHandler* m_pCHandler;
    };
    
     
    // CmdInput.cpp
    #include “CmdInput.h”
    CmdInput::CmdInput ()
    {
            m_pCHandler = NULL;
    }
    
    void CmdInput:: SetHandler(CmdHandler* pCHandler)
    {
            m_pCHandler = pCHandler;
    }
    
    int CmdInput::Run()
    {
             char cmdline[256];
             memset(cmdline, 0, 256);
             while(1)
             {
                   printf("> ");         // 输入
                   gets(cmdline);
                   if(strcmp(cmdline, "exit") == 0)   // 退出
                   {
                        break;
                   }                
               if(m_handler)                  // 解析与执行
               {
                m_handler->OnCommand(cmdline);
            }
             }
             return 0;
    }
    
    // CmdParser.h
    #include “CmdHandler.h”
    /* MyParser: 一个遵循了CmdHandler接口的类*/
    class MyParser : public CmdHandler
    {
    public:
             MyParser();
    public:
             virtual void OnCommand(char* cmdline);  // 函数接口集
    private:
             int Split(char text[], char* parts[]);        // 解析命令
    };
    
    // CmdParser.cpp
    #include <stdio.h>
    #include “CmdParser.h”
    CmdParser::CmdParser ()
    {
    }
    
    void CmdParser::OnCommand(char* cmdline)
    {        
             char* argv[128];
             int argc = Split(cmdline,argv);
             if(argc > 0)
             {
                  printf("命令: %s 
    " , argv[0]);
                  printf("参数: ");
                  for(int i=1; i<argc; i++)
                  {
    
                       printf("%s ", argv[i]);
    
                  }
                       printf("
    
    ");
             }
    }
    
     
    
    int CmdParser::Split(char text[], char* parts[])
    {        
             int count = 0;        // 分段的个数
             int start = 0;         // 每一分段的首地址
             int flag = 0;           // 遍历text,标识当前是否处于有效字符
             int stop = 0;          // 是否到达结束
    
             for(int i=0; !stop ; i++)
             {
                  char ch = text[i];
                   if(ch == 0)
                         stop = 1; // 结束循环
    
                   if(ch == ',' || ch == '' || ch == ' ' || ch == '	' )
                   {
                        if(flag) // 遇到分隔符,且当前状态为flag=1
                        {
                             flag = 0;
                             text[i] = 0; // 修改为结束符,完成分段
                             parts[count] = text + start; // 记录首地址
                             count ++;                              
                         }
                    }
                    else
                    {
                          if(!flag) // 遇到有效字符,且当前状态为flag=0
                          {
                               flag = 1;
                               start = i;
                           }
                     }
             }
             return count;                //返回分段个数
    }        

    小结

      1、  纯虚函数的定义

      2、  抽象类及其实质作用:接口规范,因为它只代表了一个规范,并没有具体实现,所以它不能被实例化。

      3、  抽象类通常被多重继承,例如,一个普通的类,实现了多套接口规范,又继承于原有的父类。

      4、  抽象类的析构函数应该声明为virtual,因为它被涉及用于继承的。

  • 相关阅读:
    为linux命令添加别名
    ubuntu安装mongodb
    mysql保存中文乱码问题
    公倍数
    复制网站内容
    孪生素数
    迷宫问题
    递归连续数
    排列平方数
    基因牛
  • 原文地址:https://www.cnblogs.com/MakeView660/p/6038129.html
Copyright © 2011-2022 走看看