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 \n" , argv[0]);
              printf("參數: ");
              for(int i=1; i<argc; i++)
              {

                   printf("%s ", argv[i]);

              }
                   printf("\n\n");
         }
}

 

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 == '\0' || ch == ' ' || ch == '\t' )
               {
                    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,因為它被涉及用於繼承的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM