
为了说明多态性,请看下面的程序:
//Inheritance4.h 的内容#include <string>#include <memory>using namespace std;enum class discipline { ARCHEolOGY,BIolOGY,COmpuTER_SCIENCE };enum class Classification { FRESHMAN,SOPHOMORE,JUNIOR,SENIOR };class Person{ protected: string name; public: Person() { setname(""); } Person(const string& pname) { setname(pname); } voID setname(const string& pname) { name = pname; } string getname() const { return name; }};class Student:public Person{ private: discipline major; shared_ptr<Person> advisor; public: Student(const string& sname,discipline d,const shared_ptr<Person>& adv) : Person(sname) { major = d; advisor = adv; } voID setMajor(discipline d) { major = d; } discipline getMajor() const { return major; } voID setAdvisor(shared_ptr<Person> p) { advisor = p; } shared_ptr<Person> getAdvisor() const { return advisor; }};class Faculty :public Person{ private: discipline department; public: Faculty(const string& fname,discipline d) : Person(fname) { department = d; } voID setDepartment(discipline d) { department = d; } discipline getDepartment() const { return department; }};class TFaculty : public Faculty{ private: string Title; public: TFaculty(const string& fname,string Title):Faculty(fname,d) { setTitle(Title); } voID setTitle (const string& Title) { this->Title = Title; } // OverrIDe getname() string getname() const { return Title + " " + Person::getname(); }};//main主程序// This exhibits the default non-polymorphic behavior of C++.#include "inheritance4.h"#include <vector>#include <iostream>using namespace std;int main(){ // Create a vector of pointers to Person objects vector<shared_ptr<Person>> people { make_shared<TFaculty> ("Indiana Jones",discipline::ARCHEolOGY,"Dr."),make_shared<Student>("Thomas Cruise",discipline::COmpuTER_SCIENCE,nullptr),make_shared<Faculty>("James Stock",discipline::BIolOGY),make_shared<TFaculty>("Sharon Rock",discipline::BIolOGY,"Professor"),make_shared<TFaculty>("Nicole Eweman","Dr.") }; // Print the names of the Person objects for (int k = 0; k < people.size (); k++) { cout << people[k]->getname() << endl; } return 0;}程序输出结果:Indiana Jones
Thomas Cruise
James Stock
Sharon Rock
Nicole Eweman
请注意,即使 TFaculty 对象具有自己的更特殊化的版本,程序也会为数组中的所有对象调用 Person 版本的 getname 函数。这段代码显然不是多态的,因为它为每个对象执行相同的成员函数,而不管它的类型如何。换句话说,对于不同类型的对象,其表现却并无不同。
为了更好地理解所发生的事情,现在来仔细看一看这 5 次调用中每一次所发生的情况。
people[k]->getname();
该函数用于检索要打印的名称。在每次调用中,指向基类 Person 的指针 people[k] 用于调用不同派生类的对象中的 getname 函数。其中的一些类,如 TFaculty,提供了更特殊化的版本来覆盖 getname 函数。当 people[k] 指向 TFaculty 对象时,编译器必须在 Person 中定义的 getname 与 TFaculty 中定义的 getname 之间进行选择。Person 是指针所属的类,TFaculty 是对象实际所属的类。前面已经介绍过,当一个指向基类的指针被用于访问被派生类覆盖的成员函数时,默认的 C++ 行为是使用指针所在类中定义的函数版本,而不是对象所属类中的版本。所以,这里编译器选择的是在 Person 中定义的 getname 函数,这也是函数的5次调用,虽然对象类型不同,但是表现却相同的原因。
在面向对象编程中,通过基类指针调用派生类对象的成员函数的情况是很常见的。假设有一个基类 B,它有一个成员函数为基类指针 ptr 指向派生类 D 的一个对象。该示例语句如下:
class B { public: voID mfun() { cout << "Base class version"; }};class D : public B{ public: voID mfun() { cout << "Derived class version"; }};shared_ptr<Base> ptr = make_shared<D>();根据前面的介绍可知,此时如果写入以下语句,那么将被调用的应该是基类 B 的成员函数而不是派生类 D 的成员函数:ptr->mfun()
如果想让编译器选择使用派生类 D 中更特殊化的 mfun() 版本,那该怎么办呢?在 C++ 中,可以通过将 mfun() 声明为基类中的虚函数来执行此 *** 作。C++ 中使用虚函数来支持多态行为。因此,为了实现基类 B 及其所有派生类中 mfun() 函数的多态行为,必须修改基类 B 中的定义如下:class B{ public: virtual voID mfun() { cout << "Base class version"; }};虚拟特性是可继承的。即如果派生类的成员函数覆盖了基类中的虚函数,那么该成员函数也会自动虚拟它本身。因此,在基类 B 中将 mfun 声明为虚函数,也将使 D 以及所有从 D 中派生的类中的 mfun 函数变成虚函数。虽然没有必要,但是很多程序员都会使用 virtual 关键字来标记所有的虚函数,以便更容易地识别它们。这是很好的做法,因此,D 的定义应该如下:
class D : public B{ public: virtual voID mfun() { cout << "Derived class version"; }};在本示例中,虚函数己经定义在类声明中。如果虚函数定义在类声明之外,则 virtual 关键字将继续对其类中声明有效,而对定义无效。C++ 不允许在类外面定义虚函数时加 virtual 关键字。以下程序是文章开头程序的修改版。其中,Person 类的 getname 函数己经声明为虚函数。它还包含了 inheritance5.h 文件,这是 inheritance4.h 文件的修改版,并且已经将 Person 类的 getname 函数变成了虚函数。
//inheritance5.h 的内容#include <string>#include <memory>using namespace std;enum class discipline { ARCHEolOGY,SENIOR };class Person{ protected: string name; public: Person() { setname(""); } Person(const string& pname) { setname(pname); } voID setname(const string& pname) { name = pname; } //virtual function virtual string getname() const { return name; }};class Student:public Person{ private: discipline major; shared_ptr<Person> advisor; public: Student(const string& sname,const shared_ptr<Person>& adv) : Person(sname) { major = d; advisor = adv; } voID setMajor(discipline d) { major = d; } discipline getMajor() const { return major; } voID setAdvisor(shared_ptr<Person>& p) { advisor = p; } shared_ptr<Person> getAdvisor() const { return advisor; }};class Faculty :public Person{ private: discipline department; public: Faculty(const string& fname,const string& Title):Faculty(fname,d) { setTitle(Title); } voID setTitle (const string& Title) { this->Title = Title; } // OverrIDe getname() string getname() const { return Title + " " + Person::getname(); }};//main主程序// This exhibits the default non-polymorphic behavior of C++.#include "inheritance5.h"#include <vector>#include <iostream>using namespace std;int main(){ // Create a vector of pointers to Person objects vector<shared_ptr<Person>> people { make_shared<TFaculty> ("Indiana Jones","Dr.") }; // Print the names of the Person objects for (int k = 0; k < people.size (); k++) { cout << people[k]->getname() << endl; } return 0;}程序输出结果:Dr. Indiana Jones
Thomas Cruise
James Stock
Professor Sharon Rock
Dr. Nicole Eweman
以上是内存溢出为你收集整理的C++多态和虚函数详解全部内容,希望文章能够帮你解决C++多态和虚函数详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)