1. 程式人生 > >C++ 虛擬函式的一個應用場景及其重要性

C++ 虛擬函式的一個應用場景及其重要性

主要用來實現所謂的多型……我個人水平低,對於這些東西一直是沒有非常的理解。

隨著使用C++的時間變長,接觸的程式碼變多,越來越多地感覺到虛擬函式的重要作用。這裡我列舉出一個例子,供大家學習。

首先我假定讀者對於虛擬函式是有一定了解的,最起碼虛擬函式是什麼,基本作用是什麼要知道,如果不知道請參看上面的連結,或任何一本講C++的書。

開始:例子來源於qgis的C++外掛

——————————————————————————————————————————————————

一、外掛類 的基類

class QgisPlugin

在類定義中請注意 幾個純虛擬函式:

    virtual void initGui() = 0;
    //! Unload the plugin and cleanup the GUI


    virtual void unload() = 0;

這兩個函式實現的是外掛圖形初始化以及外掛解除安裝。

QgisPlugin.h

class QgisPlugin
{
  public:
    QgisPlugin( QString const & name = "",
                QString const & description = "",
                QString const & category = "",
                QString const & version = "",
                PLUGINTYPE const & type = MAPLAYER )
        : mName( name ),
        mDescription( description ),
        mCategory( category ),
        mVersion( version ),
        mType( type )
    {}

    virtual ~QgisPlugin()
    {}

    //! Get the name of the plugin
    QString const & name() const
    {
      return mName;
    }

    QString       & name()
    {
      return mName;
    }

    //! Version of the plugin
    QString const & version() const
    {
      return mVersion;
    }

    //! Version of the plugin
    QString & version()
    {
      return mVersion;
    }

    //! A brief description of the plugin
    QString const & description() const
    {
      return mDescription;
    }

    //! A brief description of the plugin
    QString       & description()
    {
      return mDescription;
    }

    //! Plugin category
    QString const & category() const
    {
      return mCategory;
    }

    //! Plugin category
    QString       & category()
    {
      return mCategory;
    }

    //! Plugin type, either UI or map layer
    QgisPlugin::PLUGINTYPE const & type() const
    {
      return mType;
    }


    //! Plugin type, either UI or map layer
    QgisPlugin::PLUGINTYPE       & type()
    {
      return mType;
    }

    /// function to initialize connection to GUI
    virtual void initGui() = 0;

    //! Unload the plugin and cleanup the GUI
    virtual void unload() = 0;

  private:

    /// plug-in name
    QString mName;

    /// description
    QString mDescription;

    /// category
    QString mCategory;

    /// version
    QString mVersion;

 
}; // class QgisPlugin
二、 繼承自QgisPlugin的外掛類 ClientWindow

ClientWindow繼承了QgisPlugin

實現了 initGui(); 和 unload(); 

ClientWindow.h

class ClientWindow: public QObject, public QgisPlugin
{
    Q_OBJECT
  public:


    ClientWindow( QgisInterface * theInterface );
    //! Destructor
    virtual ~ClientWindow();
  public slots:
    //! init the gui
    virtual void initGui();
    //! Show the dialog box
    void run();
    //! unload the plugin
    void unload();
    //! show the help document
    void help();

  private:

    int mPluginType;
    //! Pointer to the QGIS interface object
    QgisInterface *mQGisIface;
    //!pointer to the qaction for this plugin
    QAction * mQActionPointer;

	msgsprite::cMsgSprite *msg;
  
};

ClientWindow.cpp

在這裡面實現了這2個函式。

void ClientWindow::initGui()
{
  // Create the action for tool
  mQActionPointer = new QAction( QIcon( ":/clientwindow/clientwindow.png" ), tr( "client window" ), this );
  // Set the what's this text
  mQActionPointer->setToolTip(tr( "即時通訊" ));
  // Connect the action to the run
  connect( mQActionPointer, SIGNAL( triggered() ), this, SLOT( run() ) );
  // Add the icon to the toolbar
  mQGisIface->addToolBarIcon( mQActionPointer );
  mQGisIface->addPluginToMenu( tr( "&show client window" ), mQActionPointer );

}

// Unload the plugin by cleaning up the GUI
void ClientWindow::unload()
{
  // remove the GUI
  mQGisIface->removePluginMenu( "&show client window", mQActionPointer );
  mQGisIface->removeToolBarIcon( mQActionPointer );
  delete mQActionPointer;
}

三、主程式中的外掛載入過程

在主程式中,cf是生成外掛例項的函式,返回new出來的一個外掛例項指標。

通過呼叫QgisPlugin *型別的基類指標pl->initGui()來呼叫外掛中的initGui()函式。

        QgisPlugin *pl = cf( mQgisInterface );
        if ( pl )
        {
          pl->initGui();
         }

------------------------------------------------------------------------------------------------------------------------------------------------------------

不知道您看明白了沒有,再總結一下:

class QgisPlugin 是基類,其中有虛擬函式

virtual void initGui() = 0;
virtual void unload() = 0;

外掛類class ClientWindow繼承了QgisPlugin 並實現了這兩個函式

主程式通過一個QgisPlugin * 基類指標 pl->呼叫initGui(),這個時候呼叫的函式其實是ClientWindow中的initGui()函式。

這就實現了多型,也就是說外掛類可能有多種,只要是繼承了QgisPlugin 的都要實現這兩個虛擬函式,而主程式中不需要知道具體的類到底是什麼,只需要用一個類似於介面的基類QgisPlugin 指標可呼叫子類(在這裡是一個外掛)中的相關的函式。

這就是虛擬函式的功勞!除此之外不使用虛擬函式的話,你要如何實現呢?