本篇文章主要介紹了C++中的普通成員函數、虛函數以及純虛函數,非常的詳細,有需要的朋友可以參考下
普通成員函數是靜態編譯的,沒有運行時多態,只會根據指針或引用的“字面值”類對象,調用自己的普通函數;虛函數為了重載和多態的需要,在基類中定義的,即便定義為空;純虛函數是在基類中聲明的虛函數,它可以再基類中有定義,且派生類必須定義自己的實現方法。
假設我們有三個類Person、Teacher、Student它們之間的關系如下:
類的關系圖
普通成員函數
【Demo1】
根據這個類圖,我們有下面的代碼實現
- #ifndef __OBJEDT_H__
- #define __OBJEDT_H__
- #include <string>
- #include <iostream>
- class Person
- {
- public:
- Person(const string& name, int age) : m_name(name), m_age(age)
- {
- }
- void ShowInfo()
- {
- cout << "姓名:" << m_name << endl;
- cout << "年齡:" << m_age << endl;
- }
- protected:
- string m_name; //姓名
- int m_age; //年齡
- };
- class Teacher : public Person
- {
- public:
- Teacher(const string& name, int age, const string& title)
- : Person(name, age), m_title(title)
- {
- }
- void ShowInfo()
- {
- cout << "姓名:" << m_name << endl;
- cout << "年齡:" << m_age << endl;
- cout << "職稱:" << m_title << endl;
- }
- private:
- string m_title; //職稱
- };
- class Student : public Person
- {
- public:
- Student(const string& name, int age, int studyId)
- : Person(name, age), m_studyId(studyId)
- {
- }
- void ShowInfo()
- {
- cout << "姓名:" << m_name << endl;
- cout << "年齡:" << m_age << endl;
- cout << "學號:" << m_studyId << endl;
- }
- private:
- int m_studyId; //學號
- };
- #endif //__OBJEDT_H__
測試代碼:
- void test()
- {
- Person* pPerson = new Person("張三", 22);
- Teacher* pTeacher = new Teacher("李四", 35, "副教授");
- Student* pStudent = new Student("王五", 18, 20151653);
- pPerson->ShowInfo();
- cout << endl;
- pTeacher->ShowInfo();
- cout << endl;
- pStudent->ShowInfo();
- cout << endl;
- delete pPerson;
- delete pTeacher;
- delete pStudent;
- }
結果:
姓名:張三
年齡:22
姓名:李四
年齡:35
職稱:副教授
姓名:王五
年齡:18
學號:20151653
說明:
這里的ShowInfo就是一個普通的函數。pPerson、pTeacher和pStudent三個對象調用ShowInfo分別展示自己的信息。
我們知道:父類的指針是可以指向子類的對象的。我們把上面的測試代碼稍微改一下:
【Demo2】
- void test()
- {
- Person* pPerson = new Person("張三", 22);
- Person* pTeacher = new Teacher("李四", 35, "副教授");
- Person* pStudent = new Student("王五", 18, 20151653);
- pPerson->ShowInfo();
- cout << endl;
- pTeacher->ShowInfo();
- cout << endl;
- pStudent->ShowInfo();
- cout << endl;
- delete pPerson;
- delete pTeacher;
- delete pStudent;
- }
結果:
姓名:張三
年齡:22
姓名:李四
年齡:35
姓名:王五
年齡:18
這時,pTeacher和pStudent只輸出了姓名和年齡,并沒有輸出子類所具有的特性(職稱和學號)。這應該不是你期望的結果,你可能期望pTeacher和pStudent輸出老師和學生的完整信息,這時就需要用虛函數。
虛函數
我們把Person中的ShowInfo成員改成虛函數(在前面加上virtual),代碼如下:
【Demo3】
- class Person
- {
- public:
- Person(const string& name, int age) : m_name(name), m_age(age)
- {
- }
- virtual void ShowInfo()
- {
- cout << "姓名:" << m_name << endl;
- cout << "年齡:" << m_age << endl;
- }
- protected:
- string m_name; //姓名
- int m_age; //年齡
- };
在執行上面【Demo2】中的測試代碼,得到我們想到的結果:
姓名:張三
年齡:22
姓名:李四
年齡:35
職稱:副教授
姓名:王五
年齡:18
學號:20151653
虛函數用法要點:
虛函數的聲明方式:virtual RETURN_TYPE functionName(ARGS 參數列表);
虛函數作用:現實C++中的多態,進行動態綁定(父類指針可指向子類的對象),直到運行時才知道要調用哪個版本(哪個類定義)的函數;
我們必要對虛函數進行定義;
一旦父類的成員函數聲明virtual,其子類的函數不管有沒有聲明為virtual,都是虛函數;
如果虛函數使用默認實參,父類和子類定義的默認實參最好一致。
【Demo4】:針對第4點說明:
- class Person
- {
- public:
- Person(const string& name, int age) : m_name(name), m_age(age)
- {
- }
- virtual void ShowInfo()
- {
- cout << "姓名:" << m_name << endl;
- cout << "年齡:" << m_age << endl;
- }
- string GetName(); //正確,普通函數如果不被使用,可以只有聲明沒有定義
- virtual int GetAge(); //錯誤,虛函數必須要有定義,即使是一個空實現,因為編譯器無法確定會使用哪個函數
- protected:
- string m_name; //姓名
- int m_age; //年齡
- };
【Demo5】:針對第5點進行說明:
設計我們的類如下定義。
- class Person
- {
- public:
- virtual void SetAge(int age = 0)
- {
- m_age = age;
- }
- //... 省略
- };
- class Teacher : public Person
- {
- public:
- virtual void SetAge(int age = 1)
- {
- m_age = age;
- }
- //... 省略
- };
- class Student : public Person
- {
- public:
- virtual void SetAge(int age = 2)
- {
- m_age = age;
- }
- //... 省略
- };
測試1:
- void test()
- {
- Person* pPerson = new Person("張三", 22);
- Teacher* pTeacher = new Teacher("李四", 35, "副教授");
- Student* pStudent = new Student("王五", 18, 20151653);
- pPerson->SetAge();
- pTeacher->SetAge();
- pStudent->SetAge();
- pPerson->ShowInfo();
- cout << endl;
- pTeacher->ShowInfo();
- cout << endl;
- pStudent->ShowInfo();
- cout << endl;
- delete pPerson;
- delete pTeacher;
- delete pStudent;
- }
結果:
姓名:張三
年齡:0
姓名:李四
年齡:1
職稱:副教授
姓名:王五
年齡:2
學號:20151653
測試2:
- void test()
- {
- Person* pPerson = new Person("張三", 22);
- Person* pTeacher = new Teacher("李四", 35, "副教授");
- Person* pStudent = new Student("王五", 18, 20151653);
- pPerson->SetAge();
- pTeacher->SetAge();
- pStudent->SetAge();
- pPerson->ShowInfo();
- cout << endl;
- pTeacher->ShowInfo();
- cout << endl;
- pStudent->ShowInfo();
- cout << endl;
- delete pPerson;
- delete pTeacher;
- delete pStudent;
- }
結果:
姓名:張三
年齡:0
姓名:李四
年齡:0
職稱:副教授
姓名:王五
年齡:0
學號:20151653
純虛函數
在上面的例子中,我們假設所有的人都要工作,但不同的人工作的方式不同。于是我們就要強制要求繼承自Person的子類都要有工作的方法,這就需要純虛函數。定義如下:
【Demo6】
- class Person
- {
- public:
- //... 省略
- virtual void DoWork() = 0;
- //... 省略
- };
但此時我們編譯
- Person* pPerson = new Person("張三", 22);
這句話時會報錯:error C2259: ‘Person' : cannot instantiate abstract class
這是因為我們并沒有為Person實現DoWork方法,而包含純虛函數的類是一個抽象的類,抽象類不能被實例化。
于是我們在子類中對它實現如下:
【Demo7】
- class Teacher : public Person
- {
- public:
- //... 省略
- virtual void DoWork()
- {
- cout << "教書..." << endl;
- }
- //... 省略
- };
- class Student : public Person
- {
- public:
- //... 省略
- virtual void DoWork()
- {
- cout << "學習..." << endl;
- }
- //... 省略
- };
沒用DoWork方法:
- void test()
- {
- Person* pTeacher = new Teacher("李四", 35, "副教授");
- Person* pStudent = new Student("王五", 18, 20151653);
- pTeacher->DoWork();
- cout << endl;
- pStudent->DoWork();
- cout << endl;
- delete pTeacher;
- delete pStudent;
- }
結果:
教書…
學習…
純虛函數用法要點:
純虛函數的聲明方式:virtual RETURN_TYPE functionName(ARGS 參數列表) = 0;
含有純虛函數的類是一個抽象的類,抽象類不能被實例化。
包含純虛函數的抽象類常用來當作對外的接口,說明這個類有什么功能,而沒有具體的實現,基體的實現交由子類完成。
通過以上對普通成員函數、虛函數以及純虛函數的介紹,希望可以對大家有所幫助。
新聞熱點
疑難解答