純虛函數和抽象類
定義
注意抽象類不能創建對象,但是可以定義一個指針
注意抽象類不能有任何成員結構, 成員函數必須協成純虛函數,
virtual 返回值 函數名(參數列表)=0
注意
含有純虛函數的類被稱為抽象類。抽象類只能作為派生類的基類,不能定義對象,但可以定義指針。在派生類實現該純虛函數后,定義抽象類對象的指針,並指向或引用子類對象。
1)在定義純虛函數時,不能定義虛函數的實現部分;
2)在沒有重新定義這種純虛函數之前,是不能調用這種函數的。
抽象類的唯一用途是為派生類提供基類,純虛函數的作用是作為派生類中的成員函數的基礎,並實現動態多態性。繼承於抽象類的派生類如果不能實現基類中所有的純虛函數,那么這個派生類也就成了抽象類。因為它繼承了基類的抽象函數,只要含有純虛函數的類就是抽象類。純虛函數已經在抽象類中定義了這個方法的聲明,其它類中只能按照這個接口去實現。
抽象類實例
計算圖形面積

#include <iostream> using namespace std; // 重點 // 面向抽象類編程(面向一套預先定義好的接口編程) // 解耦合。。模塊的划分 class Figure // 抽象類 { public: // 約定一個統一的界面(接口) 讓子類使用,讓子類必須去實現 virtual void getArea() = 0; // 純虛函數 protected: private: }; class Circle : public Figure { public: Circle(int a, int b) { this->a = a; this->b = b; } virtual void getArea() { cout << "圓的面積\t" << 3.14 * a * a << endl; } protected: private: int a; int b; }; class Sanjiao : public Figure { public: Sanjiao(int a, int b) { this->a = a; this->b = b; } virtual void getArea() { cout << "三角形的面積\t" << a * b / 2 << endl; } protected: private: int a; int b; }; class Squre : public Figure { public: Squre(int a, int b) { this->a = a; this->b = b; } virtual void getArea() { cout << "四邊形的面積\t" << a * b << endl; } protected: private: int a; int b; }; void PlayObj(Figure *base) { base->getArea(); // 會發生多態 } int main() { // Figure f1; // 抽象類不能被實例化 Figure *base = NULL; Circle c1(1, 2); Squre sq(1, 2); Sanjiao s1(2, 4); PlayObj(&c1); PlayObj(&s1); PlayObj(&sq); return 0; }
計算程序員工資
忘記了手動調用delete,讓其調用析構函數比較好
第二個有點錯誤, 不能說是抽象類

#include <iostream> using namespace std; /* 編寫一個c++程序 計算程序員工資(programer) 1要求:能計算出初級程序員工資(junior_programer),中級程序員(mid_programer),高級程序員(Adv_progreamer) 2要求利用抽象類統一界面(方便程序拓展),比如新增 計算架構師architect的工資 */ // 程序員抽象類 class programer { public: virtual void getSal() = 0; // 抽象類接口 }; // 初級程序員 class junior_programer: public programer { public: junior_programer(char *name, char *job, int sal) // 淺拷貝 { this->name = name; this->job = job; this->sal = sal; } virtual void getSal() // 接口類實現 { cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl; } private: char *name; char *job; int sal; }; // 中級程序員 class mid_programer: public programer { public: mid_programer(char *name, char *job, int sal) // 淺拷貝 { this->name = name; this->job = job; this->sal = sal; } virtual void getSal() // 接口類實現 { cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl; } private: char *name; char *job; int sal; }; // 高級程序員 class Adv_programer: public programer { public: Adv_programer(char *name, char *job, int sal) // 淺拷貝 { this->name = name; this->job = job; this->sal = sal; } virtual void getSal() // 接口類實現 { cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl; } private: char *name; char *job; int sal; }; // 后來增加的 架構師類 class architect: public programer { public: architect(char *name, char *job, int sal) // 淺拷貝 { this->name = name; this->job = job; this->sal = sal; } virtual void getSal() // 接口類實現 { cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl; } private: char *name; char *job; int sal; }; // 計算函數,簡單框架 void jisuan(programer *base) { base->getSal(); } // 引用 void jisuan(programer &base) { base.getSal(); } int main() { junior_programer junior("張三", "初級", 5000); mid_programer mid("李四", "中級", 10000); Adv_programer adv("王五", "高級", 15000); // 系統擴展 增加代碼 架構師工資 architect arc("康總", "架構師", 30000); jisuan(&junior); jisuan(&mid); jisuan(&adv); jisuan(&arc); cout << endl; // 引用類型 auto &i = junior; auto &j = mid; auto &k = adv; auto &l = arc; jisuan(i); jisuan(j); jisuan(k); jisuan(l); return 0; }

//編寫一個c++程序 計算程序員工資(programer) //1要求:能計算出初級程序員工資(junior_programer),中級程序員(mid_programer),高級程序員(Adv_progreamer) //2要求利用抽象類統一界面(方便程序拓展),比如新增 計算架構師architect的工資 #include <iostream> #include <cstring> using namespace std; // 定義程序員類, 抽象類 class Programer { virtual double getSal() = 0; }; class Junior : Programer { public: Junior(char *name = NULL, char *job = NULL, double sal = 7000) { auto len = strlen(name); this->name = new char[len + 1]; strcpy(this->name, name); len = strlen(job); this->job = new char[len + 1]; strcpy(this->job, job); this->sal = sal; } virtual ~Junior() { delete[]name; delete[]job; sal = 0; name = NULL; job = NULL; cout << "j" << endl; } virtual double getSal() { cout << this->name << " : " << this->job << ": " << this->sal << endl; } public: char *name; char *job; double sal; }; class Mid : public Junior { public: Mid(char *name = NULL, char *job = NULL, double sal = 10000) : Junior(name, job, sal) { } virtual ~Mid() // 會默認調用父類的析構函數 { cout << "m" << endl; } }; // 高級的 class Adv : public Junior { public: Adv(char *name = NULL, char *job = NULL, double sal = 10000) : Junior(name, job, sal) { } virtual ~Adv() // 會默認調用父類的析構函數 { cout << "Adv" << endl; } }; void print(Junior &obj) { obj.getSal(); } int main() { Junior j("張三", "初級", 5000); Mid m("李四", "中級", 10000); Adv a("王五", "高級", 15000); print(j); print(m); print(a); return 0; }
抽象類編程
動物園類

#if 0 // main.cpp #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include "Animal.h" #include "Dog.h" #include "Cat.h" #include "Dog.cpp" #include "Cat.cpp" #include "Animal.cpp" using namespace std; int main(void) { letAnimalCry(new Dog); letAnimalCry(new Cat); #if 0 Animal *dog = new Dog; letAnimalCry(dog); delete Dog; #endif return 0; } #endif // -- Animal.h #if 0 #pragma once #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; class Animal { public: //純虛函數,讓子類繼承並且實現 virtual void voice() = 0; Animal(); virtual ~Animal(); }; //架構函數 //讓動物叫 void letAnimalCry(Animal *animal); #endif // Animal.cpp #if 0 #include "Animal.h" inline Animal::Animal() { cout << "animal().." << endl; } inline Animal::~Animal() { cout << "~Animal()..." << endl; } inline void letAnimalCry(Animal *animal) { animal->voice(); // 需要手動調用delete 讓其調用析構函數 if (animal != NULL) { delete animal; } } #endif // Dog.h------------------------ #if 0 #pragma once #include "Animal.h" class Dog : public Animal { public: Dog(); ~Dog(); virtual void voice(); }; #endif // Dog.cpp #if 0 #include "Dog.h" inline Dog::Dog() { cout << "Dog().." << endl; } inline Dog::~Dog() { cout << "~Dog().." << endl; } inline void Dog::voice() { cout << "狗開始哭了, 555" << endl; } #endif // Cat.h #if 0 #pragma once #include "Animal.h" class Cat : public Animal { public: Cat(); ~Cat(); virtual void voice(); }; #endif // Cat.cpp #if 0 #include "Cat.h" inline Cat::Cat() { cout << "cat().." << endl; } inline Cat::~Cat() { cout << "~cat().." << endl; } inline void Cat::voice() { cout << "小貓開始哭了,66666" << endl; } #endif
電腦類實例:

#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; //-------- 抽象層--------- //抽象CPU類 class CPU { public: // CPU(); virtual void caculate() = 0; }; //抽象的card類 class Card { public: virtual void display() = 0; }; //抽象的內存類 class Memory { public: virtual void storage() = 0; }; //架構類 class Computer { public: Computer(CPU *cpu, Card *card, Memory *mem) { this->cpu = cpu; this->card = card; this->mem = mem; } void work() { this->cpu->caculate(); this->card->display(); this->mem->storage(); } ~Computer() { if (this->cpu != NULL) { cout << "~cpu" << endl; delete this->cpu; } if (this->card != NULL) { cout << "~card"<<endl; delete this->card; } if (this->mem != NULL) { cout << "~mem"<<endl; delete this->mem; } } private: CPU *cpu; Card *card; Memory *mem; }; // -------------------------- //-----------實現層---------- //具體的IntelCPU class IntelCPU : public CPU { public: virtual void caculate() { cout << "Intel CPU開始計算了" << endl; } }; class IntelCard : public Card { public: virtual void display() { cout << "Intel Card開始顯示了" << endl; } }; class IntelMem : public Memory { public: virtual void storage() { cout << "Intel mem開始存儲了" << endl; } }; class NvidiaCard : public Card { public: virtual void display() { cout << "Nvidia 顯卡開始顯示了" << endl; } }; class KingstonMem : public Memory { public: virtual void storage() { cout << "KingstonMem 開始存儲了" << endl; } }; //-------------------------- void test() { Computer *com1 = new Computer(new IntelCPU, new IntelCard, new IntelMem); com1->work(); delete com1; // 如果定義一個指針不要忘記釋放 } //--------業務層------------------- int main() { //1 組裝第一台intel系列的電腦 #if 0 CPU *intelCpu = new IntelCPU; Card *intelCard = new IntelCard; Memory *intelMem = new IntelMem; Computer *com1 = new Computer(intelCpu, intelCard, intelMem); com1->work(); Card *nCard = new NvidiaCard; Memory* kMem = new KingstonMem; Computer *com2 = new Computer(intelCpu, nCard, kMem); com2->work(); delete intelCpu; #endif // Computer *com1 = new Computer(new IntelCPU, new IntelCard, new IntelMem); // com1->work(); // delete com1; // 這里不要忘記釋放 test(); return 0; }
圓類

#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; //抽象的圖形類 class Shape { public: //打印出圖形的基本你屬性 virtual void show() = 0; //得到圖形的面積 virtual double getArea() = 0; virtual ~Shape() { } }; //圓類 class Circle :public Shape { public: Circle(double r) { this->r = r; } //打印出圖形的基本你屬性 virtual void show() { cout << "圓的半徑是 " << r << endl; } //得到圖形的面積 virtual double getArea() { cout << "獲取圓的面積" << endl; return this->r*this->r *3.14; } ~Circle() { cout << "圓的析構函數。。" << endl; } private: double r; }; class Square :public Shape { public: Square(double a) { this->a = a; } //打印出圖形的基本你屬性 virtual void show() { cout << "正方形的邊長是" << this->a << endl; } //得到圖形的面積 virtual double getArea() { cout << "得到正方形的面積" << endl; return a*a; } ~Square() { cout << "正方形的析構函數" << endl; } private: double a; }; int main(void) { Shape *array[2] = { 0 }; for (int i = 0; i < 2; i++) { //生成一個圓 if (i == 0) { double r; cout << "請輸入圓的半徑" << endl; cin >> r; array[i] = new Circle(r); } //生成一個正方形 else { double a; cout << "請輸入正方形的邊長" << endl; cin >> a; array[i] = new Square(a); } } //遍歷這個array數組 for (int i = 0; i < 2; i++) { array[i]->show(); cout << array[i]->getArea() << endl; delete array[i]; } return 0; }
比較大的例子,推薦看看
多態練習, 企業信息管理
https://i.cnblogs.com/Files.aspx
函數指針與多態
函數指針基礎

#include <cstdio> #include <cstdlib> #include <cstring> // 數組類型, 基本語法知識梳理 // 定義一個數組類型 // int arr[10]; // 定義一個指針數組類型 // 定義一個指向 數組類型的指針, 數組類的指針 int main() { int a[10]; // a代表數組首元素地址, &a 代表整個數組的地址 // a+1 代表步長加4個單元,就是a[1]的地址, // &a+1 代表步長加40個單元后的地址 // { // 定義數組類型 typedef int (myTypeArr)[10]; myTypeArr myArr; myArr[0] = 10; printf("%d\n", myArr[0]); } { // 定義一個指針數組類型 typedef int (*PTypeArray)[10]; // int * p PTypeArray myPArray; // sizeof(int) * 10; 步長, myPArray 是一個二級指針 myPArray = &a; // 相當於 // int b = 10; // int *c = NULL; // c = &b; (*myPArray)[0] = 20; // 注意這里 printf("%d\n", a[0]); } { // 定義一個指向 數組類型的指針, 數組類的指針 int (*MyPoint)[10]; // 告訴c編譯器給我分配內存 MyPoint = &a; (*MyPoint)[0] = 40; printf("%d\n", a[0]); } return 0; } // 函數指針語法知識梳理 // 如何定義一個函數類型 // 如何定義一個函數指針類型 // 如何定義一個函數指針(指向一個函數入口地址) int add(int a, int b) { printf("func add...\n"); return a + b; } int main01() { add(1, 2); // 直接調用// 函數名就是函數入口地址 // 如何定義一個函數類型 { typedef int (myFuncType)(int a, int b); // 定義一個類型 myFuncType *myFuncTypePoint = NULL; // 定義了一個指針,指向某一種類的函數 myFuncTypePoint = &add; // 細節,這里的&add &可以不加 myFuncTypePoint(1, 2); // 間接調用 } // 定義一個函數指針類型 { typedef int (*MyPointFuncType)(int a, int b); // int *a = NULL; MyPointFuncType myPointFunc = NULL; // 定義一個指針 myPointFunc = add; myPointFunc(1, 2); } // 函數指針 { int (*myPointFunc)(int a, int b); // 定義一個變量 myPointFunc = add; myPointFunc(1, 2); } }

#include <stdio.h> #include <stdlib.h> #include <string.h> int myAdd(int a, int b) { printf("func myAdd...\n"); return a + b; } int myAdd2(int a, int b) // 相當於虛函數表 { printf("func myAdd2...\n"); return a + b; } // 定義了一個類型 typedef int (*myTypeFuncAdd)(int a, int b); // mainop都是函數指針做函數參數 int mainop(myTypeFuncAdd myFuncAdd) { int c = myFuncAdd(1, 2); // 間接調用 printf("mainop\n"); return c; } // int (*myTypeFuncAdd)(int a, int b); 定義一個指向某種函數的指針 int mainop2(int (*myTypeFuncAdd)(int a, int b)) { int c = myTypeFuncAdd(1, 2); // 間接調用 printf("mainop2\n"); return c; } // 間接調用 // 任務的調用,和任務的編寫可以分開 int main() { /* myTypeFuncAdd myfuncAdd = myAdd; myfuncAdd(1, 3); // 直接調用 mainop(myAdd); mainop2(myAdd); */ mainop(myAdd); mainop(myAdd2); // 相當於發生了多態,函數指針做函數參數 return 0; }

#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; int func(int a, int b) { cout << " 1999 年寫的 func" << endl; return 0; } int func2(int a, int b) { cout << "1999 寫的 func2" << endl; return 0; } int func3(int a, int b) { cout << "1999年 寫的 func3 " << endl; return 0; } //2018想添加一個新的子業務 int new_func4(int a, int b) { cout << "2018 新寫的子業務" << endl; cout << "a = " << a << ", b = " << b << endl; return 0; } //方法一: 函數的返回值, 函數的參數列表(形參的個數,類型,順序) //定義一個函數類型。 typedef int(FUNC)(int, int); //方法二: 定義一個函數指針 typedef int(*FUNC_P)(int, int); //定義一個統一的接口 將他們全部調用起來。 void my_funtion(int(*fp)(int, int), int a, int b) { cout << "1999年實現這個架構業務" << endl; cout << "固定業務1" << endl; cout << "固定業務2" << endl; fp(a, b);//可變的業務 cout << "固定業務3" << endl; } int main(void) { #if 0 //方法一: FUNC *fp = NULL; fp = func; fp(10, 20); FUNC_P fp2 = NULL; fp2 = func; fp2(100, 200); //方法三: int(*fp3)(int, int) = NULL; fp3 = func; fp3(1000, 3000); #endif my_funtion(func, 10, 20); my_funtion(func2, 100, 200); my_funtion(func3, 1000, 2000); my_funtion(new_func4, 2000, 3000); return 0; }

#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; //-------------抽象層------------ //定義拆開錦囊方法的類型。 typedef void(TIPS)(void); //定義錦囊 struct tip { char from[64]; //誰寫的 char to[64];//寫給誰的。 //錦囊的內容 TIPS *tp;//相當於抽象類的 純虛函數. }; //需要一個打開錦囊的架構函數 void open_tips(struct tip *tip_p) { cout << "打開了錦囊" << endl; cout << "此錦囊是由" << tip_p->from << "寫給 " << tip_p->to << "的。" << endl; cout << "內容是" << endl; tip_p->tp(); //此時就發生了多態現象。 } //提供一個創建一個錦囊的方法 struct tip* create_tip(char*from, char *to, TIPS*tp) { struct tip *temp = (struct tip*)malloc(sizeof(struct tip)); if (temp == NULL) { return NULL; } strcpy(temp->from, from); strcpy(temp->to, to); //給一個回調函數賦值, 一般稱 注冊回調函數 temp->tp = tp; return temp; } //提供一個銷毀錦囊的方法 void destory_tip(struct tip *tp) { if (tp != NULL) { free(tp); tp = NULL; } } // ------------- 實現層------------ //諸葛亮寫了3個錦囊 void tip1_func(void) { cout << "一到東吳就拜會喬國老" << endl; } void tip2_func(void) { cout << "如果主公樂不思蜀,就謊稱曹賊來襲。趕緊回來 " << endl; } void tip3_func(void) { cout << "如果被孫權追殺,向孫尚香求救" << endl; } void tip4_func(void) { cout << "如果求救孫尚香都不靈, 你們去死了, 我是蜀國老大了" << endl; } //--------------- 業務層----------------- int main(void) { //創建出3個錦囊 struct tip *tip1 = create_tip("孔明", "趙雲", tip1_func); struct tip *tip2 = create_tip("孔明", "趙雲", tip2_func); struct tip *tip3 = create_tip("孔明", "趙雲", tip3_func); struct tip *tip4 = create_tip("龐統", "趙雲", tip4_func); //由趙雲進行拆錦囊。 cout << "剛剛來到東吳, 趙雲打開第一個錦囊" << endl; open_tips(tip1); cout << "-----------" << endl; cout << "劉備樂不思蜀, 趙雲打開第二個錦囊" << endl; open_tips(tip2); cout << "-----------" << endl; cout << "孫權大軍追殺,趙雲打開第三個錦囊" << endl; open_tips(tip3); cout << "-----------" << endl; cout << "趙雲發現,實在是殺不動了, 打開了第四個錦囊" << endl; open_tips(tip4); destory_tip(tip1); destory_tip(tip2); destory_tip(tip3); destory_tip(tip4); return 0; }
未完待續....