程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 解析C++編程中virtual聲明的虛函數和單個繼續

解析C++編程中virtual聲明的虛函數和單個繼續

編輯:關於C++

解析C++編程中virtual聲明的虛函數和單個繼續。本站提示廣大學習愛好者:(解析C++編程中virtual聲明的虛函數和單個繼續)文章只能為提供參考,不一定能成為您想要的結果。以下是解析C++編程中virtual聲明的虛函數和單個繼續正文


虛函數

虛函數是應在派生類中從新界說的成員函數。 當應用指針或對基類的援用來援用派生的類對象時,可認為該對象挪用虛函數並履行該函數的派生類版本。
虛函數確保為該對象挪用准確的函數,這與用於停止函數挪用的表達式有關。
假定基類包括聲明為 virtual 的函數,而且派生類界說了雷同的函數。 為派生類的對象挪用派生類中的函數,即便它是應用指針或對基類的援用來挪用的。 以下示例顯示了一個基類,它供給了 PrintBalance 函數和兩個派生類的完成

// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

class Account {
public:
  Account( double d ) { _balance = d; }
  virtual double GetBalance() { return _balance; }
  virtual void PrintBalance() { cerr << "Error. Balance not available for base type." << endl; }
private:
  double _balance;
};

class CheckingAccount : public Account {
public:
  CheckingAccount(double d) : Account(d) {}
  void PrintBalance() { cout << "Checking account balance: " << GetBalance() << endl; }
};

class SavingsAccount : public Account {
public:
  SavingsAccount(double d) : Account(d) {}
  void PrintBalance() { cout << "Savings account balance: " << GetBalance(); }
};

int main() {
  // Create objects of type CheckingAccount and SavingsAccount.
  CheckingAccount *pChecking = new CheckingAccount( 100.00 ) ;
  SavingsAccount *pSavings = new SavingsAccount( 1000.00 );

  // Call PrintBalance using a pointer to Account.
  Account *pAccount = pChecking;
  pAccount->PrintBalance();

  // Call PrintBalance using a pointer to Account.
  pAccount = pSavings;
  pAccount->PrintBalance();  
}

在後面的代碼中,對 PrintBalance 的挪用是雷同的,pAccount 所指向的對象除外。 因為 PrintBalance 是虛擬的,是以將挪用為每一個對象界說的函數版本。 派生類 PrintBalance 和 CheckingAccount 中的 SavingsAccount 函數“重寫”基類 Account 中的函數。
假如聲明的類不供給 PrintBalance 函數的重寫完成,則應用基類 Account 中的默許完成。
派生類中的函數僅在基類中的虛函數的類型雷同時重寫這些虛函數。 派生類中的函數不克不及只是與其前往類型中的基類的虛函數分歧;參數列表也必需分歧。
當應用指針或援用挪用函數時,以下規矩將實用:
依據為其挪用的對象的根本類型來解析對虛函數的挪用。
依據指針或援用的類型來解析對非虛函數的挪用。
以下示例解釋在經由過程指針挪用時虛函數和非虛函數的行動:

// deriv_VirtualFunctions2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

class Base {
public:
  virtual void NameOf();  // Virtual function.
  void InvokingClass();  // Nonvirtual function.
};

// Implement the two functions.
void Base::NameOf() {
  cout << "Base::NameOf\n";
}

void Base::InvokingClass() {
  cout << "Invoked by Base\n";
}

class Derived : public Base {
public:
  void NameOf();  // Virtual function.
  void InvokingClass();  // Nonvirtual function.
};

// Implement the two functions.
void Derived::NameOf() {
  cout << "Derived::NameOf\n";
}

void Derived::InvokingClass() {
  cout << "Invoked by Derived\n";
}

int main() {
  // Declare an object of type Derived.
  Derived aDerived;

  // Declare two pointers, one of type Derived * and the other
  // of type Base *, and initialize them to point to aDerived.
  Derived *pDerived = &aDerived;
  Base  *pBase  = &aDerived;

  // Call the functions.
  pBase->NameOf();      // Call virtual function.
  pBase->InvokingClass();  // Call nonvirtual function.
  pDerived->NameOf();    // Call virtual function.
  pDerived->InvokingClass(); // Call nonvirtual function.
}

輸入

Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived

請留意,不管 NameOf 函數是經由過程指向 Base 的指針照樣經由過程指向 Derived 的指針停止挪用,它都邑挪用 Derived 的函數。 它挪用 Derived 的函數,由於 NameOf 是虛函數,而且 pBase 和 pDerived 都指向類型 Derived 的對象。
因為僅為類類型的對象挪用虛函數,是以不克不及將全局函數或靜態函數聲明為 virtual。
在派生類中聲明重寫函數時可以使用 virtual 症結字,但它不是必須的;虛函數的重寫一直是虛擬的。
必需界說基類中的虛函數,除非應用 pure-specifier 聲明它們。 (有關純虛函數的具體信息,請參閱籠統類。)
可經由過程應用規模解析運算符 (::) 顯式限制函數稱號來禁用虛函數挪用機制。 斟酌先前觸及 Account 類的示例。 若要挪用基類中的 PrintBalance,請應用以下所示的代碼:

CheckingAccount *pChecking = new CheckingAccount( 100.00 );

pChecking->Account::PrintBalance(); // Explicit qualification.

Account *pAccount = pChecking; // Call Account::PrintBalance

pAccount->Account::PrintBalance();  // Explicit qualification.

在後面的示例中,對 PrintBalance 的挪用將禁用虛函數挪用機制。


單個繼續
在“單繼續”(繼續的罕見情勢)中,類僅具有一個基類。斟酌下圖中闡釋的關系。

簡略單繼續關系圖
留意該圖中從慣例到特定的進度。在年夜多半類條理構造的設計中發明的另外一個罕見特征是,派生類與基類具有“某種”關系。在該圖中,Book 是一種 PrintedDocument,而 PaperbackBook 是一種 book。
該圖中的另外一個要留意的是:Book 既是派生類(來自 PrintedDocument),又是基類(PaperbackBook 派生自 Book)。此類類條理構造的框架聲明以下面的示例所示:

// deriv_SingleInheritance.cpp
// compile with: /LD
class PrintedDocument {};

// Book is derived from PrintedDocument.
class Book : public PrintedDocument {};

// PaperbackBook is derived from Book.
class PaperbackBook : public Book {};

PrintedDocument 被視為 Book 的“直接基”類;它是 PaperbackBook 的“直接基”類。差別在於,直接基類湧現在類聲明的基本列表中,而直接基類不是如許的。
在聲明派生的類之前聲明從中派生每一個類的基類。為基類供給前向援用聲明是不敷的;它必需是一個完全聲明。
在後面的示例中,應用拜訪解釋符 public。 成員拜訪掌握中引見了公共的、受掩護的和公有的繼續的寄義。
類可用作多個特定類的基類,以下圖所示。

留意
有向非輪回圖關於單繼續不是獨一的。它們還用於表現多重繼續關系圖。 多重繼續中對本主題停止了解釋。
在繼續中,派生類包括基類的成員和您添加的一切新成員。是以,派生類可以援用基類的成員(除非在派生類中從新界說這些成員)。當在派生類中從新界說了直接或直接基類的成員時,規模解析運算符 (::) 可用於援用這些成員。請看以下示例:

// deriv_SingleInheritance2.cpp
// compile with: /EHsc /c
#include <iostream>
using namespace std;
class Document {
public:
  char *Name;  // Document name.
  void PrintNameOf();  // Print name.
};

// Implementation of PrintNameOf function from class Document.
void Document::PrintNameOf() {
  cout << Name << endl;
}

class Book : public Document {
public:
  Book( char *name, long pagecount );
private:
  long PageCount;
};

// Constructor from class Book.
Book::Book( char *name, long pagecount ) {
  Name = new char[ strlen( name ) + 1 ];
  strcpy_s( Name, strlen(Name), name );
  PageCount = pagecount;
};

請留意,Book 的結構函數 (Book::Book) 具有對數據成員 Name 的拜訪權。在法式中,可以創立和應用類型為 Book 的對象,以下所示:

// Create a new object of type Book. This invokes the
//  constructor Book::Book.
Book LibraryBook( "Programming Windows, 2nd Ed", 944 );

...

// Use PrintNameOf function inherited from class Document.
LibraryBook.PrintNameOf();

如後面的示例所示,以雷同的方法應用類成員和繼續的數據和函數。假如類 Book 的完成挪用 PrintNameOf 函數的從新完成,則只能經由過程應用規模解析 (Document) 運算符來挪用屬於 :: 類的函數:

// deriv_SingleInheritance3.cpp
// compile with: /EHsc /LD
#include <iostream>
using namespace std;

class Document {
public:
  char *Name;     // Document name.
  void PrintNameOf() {} // Print name.
};

class Book : public Document {
  Book( char *name, long pagecount );
  void PrintNameOf();
  long PageCount;
};

void Book::PrintNameOf() {
  cout << "Name of book: ";
  Document::PrintNameOf();
}

假如存在可拜訪的明白基類,則可以隱式將派生類的指針和援用轉換為其基類的指針和援用。上面的代碼應用指針演示了此概念(雷同的准繩實用於援用):

// deriv_SingleInheritance4.cpp
// compile with: /W3
struct Document {
  char *Name;
  void PrintNameOf() {}
};

class PaperbackBook : public Document {};

int main() {
  Document * DocLib[10];  // Library of ten documents.
  for (int i = 0 ; i < 10 ; i++)
   DocLib[i] = new Document;
}

在後面的示例中,創立了分歧的類型。然則,因為這些類型都派生自 Document 類,是以存在對 Document * 的隱式轉換。是以,DocLib 是“異類列表”(個中包括的一切對象並不是屬於統一類型),該列表包括分歧類型的對象。
因為 Document 類具有一個 PrintNameOf 函數,是以它可以打印庫中每本書的稱號,但它能夠會疏忽某些特定於文檔類型的信息(Book 的頁計數、HelpFile 的字節數等)。
留意
強迫應用基類來完成函數(如 PrintNameOf)平日不是最好設計。 虛函數供給其他設計替換辦法。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved