解析C++编程中virtual声明的虚函数以及单个继承
虚函数 虚函数是应在派生类中重新定义的成员函数。 当使用指针或对基类的引用来引用派生的类对象时,可以为该对象调用虚函数并执行该函数的派生类版本。 // 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 中的函数。 // 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::NameOfn"; } void Base::InvokingClass() { cout << "Invoked by Basen"; } class Derived : public Base { public: void NameOf(); // Virtual function. void InvokingClass(); // Nonvirtual function. }; // Implement the two functions. void Derived::NameOf() { cout << "Derived::NameOfn"; } void Derived::InvokingClass() { cout << "Invoked by Derivedn"; } 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 的对象。 CheckingAccount *pChecking = new CheckingAccount( 100.00 ); pChecking->Account::PrintBalance(); // Explicit qualification. Account *pAccount = pChecking; // Call Account::PrintBalance pAccount->Account::PrintBalance(); // Explicit qualification. 在前面的示例中,对 PrintBalance 的调用将禁用虚函数调用机制。
简单单继承关系图 // 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 的“间接基”类。差异在于,直接基类出现在类声明的基础列表中,而间接基类不是这样的。 注意 // 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 是“异类列表”(其中包含的所有对象并非属于同一类型),该列表包含不同类型的对象。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |