純虛函數和抽象類
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<<"圓形的面積: "<<3.14*a*a<<endl;;}private:int a;int b;
};class Tri : public Figure
{
public:Tri(int a, int b){this->a = a;this->b = b;}virtual void getArea() {cout<<"三角形的面積: "<<a*b/2<<endl;;}private:int a;int b;
};class Square : public Figure
{
public:Square(int a, int b){this->a = a;this->b = b;}virtual void getArea() {cout<<"四邊形的面積: "<<a*b<<endl;;}private:int a;int b;
};void objplay(Figure *base)
{base->getArea(); //會發生多態
}void main511()
{//Figure f; //抽象類不能被實例化Figure *base = NULL; //抽象類不能被實例化Circle c1(10, 20);Tri t1(20, 30);Square s1(50, 60);//面向抽象類編程(面向一套預先定義好的接口編程)objplay(&c1);objplay(&t1);objplay(&s1);//c1.getArea();cout<<"hello..."<<endl;system("pause");return ;
}
3.抽象類在多繼承中的應用
C++中沒有Java中的接口概念,抽象類可以模擬Java中的接口類。(接口和協議)
工程上的多繼承
- 被實際開發經驗拋棄的多繼承
- 工程開發中真正意義上的多繼承是幾乎不被使用的
- 多重繼承帶來的代碼復雜性遠多于其帶來的便利
- 多重繼承對代碼維護性上的影響是災難性的
- 在設計方法上,任何多繼承都可以用單繼承代替
多繼承中的二義性和多繼承不能解決的問題
C++沒有接口只有多繼承和抽象類
- 絕大多數面向對象語言都不支持多繼承
- 絕大多數面向對象語言都支持接口的概念
- C++中沒有接口的概念
- C++中可以使用純虛函數實現接口
- 接口類中只有函數原型定(純虛函數)義,沒有任何數據的定義。
class Interface
{public:virtual void func1() = 0;virtual void func2(int i) = 0;virtual void func3(int i) = 0;
};
實際工程經驗證明
- 多重繼承接口不會帶來二義性和復雜性等問題
- 多重繼承可以通過精心設計用單繼承和接口來代替
- 接口類只是一個功能說明,而不是功能實現。
- 子類需要根據功能說明定義功能實現。
多繼承的二義性
#include <iostream>
using namespace std;class B
{
public:int b;
protected:
private:
};class B1 : virtual public B
{
public:int b1;
protected:
private:
};class B2 : virtual public B
{
public:int b2;
protected:
private:
};class C : public B1, public B2
{
public:int c;
protected:
private:
};void main61()
{C myc;myc.c = 10;myc.b = 100;//二義性 error C2385: 對“b”的訪問不明確cout<<"hello..."<<endl;system("pause");return ;
}
- 抽象類和多繼承更配哦
#include <iostream>
using namespace std;class Interface1
{
public:virtual int add(int a, int b) = 0;virtual void print() = 0;
};class Interface2
{
public:virtual int mult(int a, int b) = 0;virtual void print() = 0;
};class Parent
{
public:int getA(){a = 0;return a;}
protected:
private:int a;
};class Child : public Parent, public Interface1, public Interface2
{
public:virtual int add(int a, int b){cout<<"Child: add()已經執行\n";return a + b;}virtual void print(){cout<<"Child: print()已經執行\n";}virtual int mult(int a, int b){cout<<"Child: mult()已經執行\n";return a*b;}
protected:
private:
};void main71()
{Child c1;c1.print();Interface1 *it1 = &c1;it1->add(1, 2);Interface2 *it2 = &c1;it2->mult(3, 6);cout<<"hello..."<<endl;system("pause");return ;
}
4.面向抽象類編程
- 計算程序猿工資
#include <iostream>
using namespace std;class programer{
public:virtual int getSal() = 0;
};class junior_programer :public programer
{
private:char *name;char *obj;int sal;
public:junior_programer(char *_name,char *_obj,int _sal){name = _name;obj = _obj;sal = _sal;}virtual int getSal(){cout << name << " " << obj << ": " << sal << endl;return sal;}
protected:
};class mid_programer :public programer
{
private:char *name;char *obj;int sal;
public:mid_programer(char *_name, char *_obj, int _sal){name = _name;obj = _obj;sal = _sal;}virtual int getSal(){cout << name << " " << obj << ": " << sal << endl;return sal;}
protected:
};class adv_programer :public programer
{
private:char *name;char *obj;int sal;
public:adv_programer(char *_name, char *_obj, int _sal){name = _name;obj = _obj;sal = _sal;}virtual int getSal(){cout << name << " " << obj << ": " << sal << endl;return sal;}
protected:
};class arch_programer :public programer
{
private:char *name;char *obj;int sal;
public:arch_programer(char *_name, char *_obj, int _sal){name = _name;obj = _obj;sal = _sal;}virtual int getSal(){cout << name << " " << obj << ": " << sal << endl;return sal;}
protected:
};void CalProgSal(programer *base)
{base->getSal();
}int main(void)
{junior_programer jp("小王", "初級", 4000);mid_programer mp("小張", "中級", 8600);adv_programer ap("小李", "高級", 15000);//系統擴展arch_programer ar("高水平學員", "架構師", 24000);CalProgSal(&jp);CalProgSal(&mp);CalProgSal(&ap);CalProgSal(&ar);cout<<"Hello!"<<endl;system("pause");return 0;
}
5.socket庫c++模型設計和實現
企業信息系統框架集成第三方產品
- 案例背景:一般的企業信息系統都有成熟的框架。軟件框架一般不發生變化,能自由的集成第三方廠商的產品。
- 案例需求:請你在企業信息系統框架中集成第三方廠商的Socket通信產品和第三方廠商加密產品。
- 第三方廠商的Socket通信產品:完成兩點之間的通信
- 第三方廠商加密產品:完成數據發送時加密;數據解密時解密。
案例要求:
1)能支持多個廠商的Socket通信產品入圍
2)能支持多個第三方廠商加密產品的入圍
3)企業信息系統框架不輕易發生框架
需求實現
- 思考1:企業信息系統框架、第三方產品如何分層
- 思考2:企業信息系統框架,如何自由集成第三方產品
(軟件設計:模塊要求松、接口要求緊) - 思考3:軟件分成以后,開發企業信息系統框架的程序員,應該做什么?第三方產品入圍應該做什么?
編碼實現
分析有多少個類 CSocketProtocol CSckFactoryImp1 CSckFactoryImp2
CEncDesProtocol HwEncdes ciscoEncdes
1、 定義 CSocketProtocol 抽象類
2、 編寫框架函數
3、 編寫框架測試函數
4、 廠商1(CSckFactoryImp1)實現CSocketProtocol、廠商2(CSckFactoryImp1)實現CSocketProtoco
5、 抽象加密接口(CEncDesProtocol)、加密廠商1(CHwImp)、加密廠商2(CCiscoImp)),集成實現業務模型
6、 框架(c語言函數方式,框架函數;c++類方式,框架類)
幾個重要的面向對象思想
* 繼承-組合(強弱)
* 注入
* 控制反轉 IOC
* MVC
* 面向對象思想擴展aop思想:aop思想是對繼承編程思想的有力的補充
實現步驟
- 定義socket的抽象類和純虛函數
#pragma once#include <iostream>
using namespace std;class CSocketProtocol
{
public:CSocketProtocol(){;}virtual ~CSocketProtocol() //虛析構函數的細節{;}//客戶端初始化 獲取handle上下virtual int cltSocketInit( /*out*/) = 0; //客戶端發報文virtual int cltSocketSend( unsigned char *buf /*in*/, int buflen /*in*/) = 0; //客戶端收報文virtual int cltSocketRev( unsigned char *buf /*in*/, int *buflen /*in out*/) = 0;//客戶端釋放資源virtual int cltSocketDestory() = 0;};
2.廠商一的功能實現
- 類的頭文件
#pragma once#include <iostream>
using namespace std;
#include "CSocketProtocol.h"class CSckFactoryImp1 : public CSocketProtocol
{
public://客戶端初始化 獲取handle上下virtual int cltSocketInit( /*out*/); //客戶端發報文virtual int cltSocketSend( unsigned char *buf /*in*/, int buflen /*in*/); //客戶端收報文virtual int cltSocketRev( unsigned char *buf /*in*/, int *buflen /*in out*/);//客戶端釋放資源virtual int cltSocketDestory();private:unsigned char *p;int len ;
};
- 類的實現文件
#include <iostream>
using namespace std;#include "CSckFactoryImp1.h"//客戶端初始化 獲取handle上下int CSckFactoryImp1::cltSocketInit( /*out*/){p = NULL;len = 0 ;return 0;}//客戶端發報文int CSckFactoryImp1::cltSocketSend( unsigned char *buf /*in*/, int buflen /*in*/){p = (unsigned char * ) malloc(sizeof(unsigned char) * buflen);if (p == NULL){return -1;}memcpy(p, buf, buflen);len = buflen;return 0;}//客戶端收報文int CSckFactoryImp1::cltSocketRev( unsigned char *buf /*in*/, int *buflen /*in out*/){if (buf==NULL || buflen==NULL){return -1;}*buflen = this->len ;memcpy(buf, this->p, this->len);return 0;}//客戶端釋放資源int CSckFactoryImp1::cltSocketDestory(){if (p != NULL){free(p);p = NULL;len = 0;}return 0;}
3.廠商二的功能實現
- 類的頭文件
#pragma once#include <iostream>
using namespace std;
#include "CSocketProtocol.h"class CSckFactoryImp2 : public CSocketProtocol
{
public://客戶端初始化 獲取handle上下virtual int cltSocketInit( /*out*/); //客戶端發報文virtual int cltSocketSend( unsigned char *buf /*in*/, int buflen /*in*/); //客戶端收報文virtual int cltSocketRev( unsigned char *buf /*in*/, int *buflen /*in out*/);//客戶端釋放資源virtual int cltSocketDestory();private:unsigned char *p;int len ;
};
- 類的實現文件
#include <iostream>
using namespace std;#include "CSckFactoryImp2.h"//客戶端初始化 獲取handle上下
int CSckFactoryImp2::cltSocketInit( /*out*/)
{p = NULL;len = 0 ;return 0;
}//客戶端發報文
int CSckFactoryImp2::cltSocketSend( unsigned char *buf /*in*/, int buflen /*in*/)
{p = (unsigned char * ) malloc(sizeof(unsigned char) * buflen);if (p == NULL){return -1;}memcpy(p, buf, buflen);len = buflen;return 0;
}//客戶端收報文
int CSckFactoryImp2::cltSocketRev( unsigned char *buf /*in*/, int *buflen /*in out*/)
{if (buf==NULL || buflen==NULL){return -1;}*buflen = this->len ;memcpy(buf, this->p, this->len);return 0;
}//客戶端釋放資源
int CSckFactoryImp2::cltSocketDestory()
{if (p != NULL){free(p);p = NULL;len = 0;}return 0;
}
4.測試socket功能文件
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;#include "CSocketProtocol.h"
#include "CSckFactoryImp1.h"
#include "CSckFactoryImp2.h"//面向抽象類編程,框架實現完畢
int SckSendAndRec01(CSocketProtocol *sp, unsigned char *in, int inlen, unsigned char *out, int *outlen)
{int ret = 0;ret = sp->cltSocketInit();if (ret != 0){goto End;}ret = sp->cltSocketSend(in, inlen);if (ret != 0){goto End;}ret = sp->cltSocketRev(out, outlen);if (ret != 0){goto End;}End:ret = sp->cltSocketDestory();return 0;
}//寫一個框架
int main011()
{int ret = 0;unsigned char in[4096];int inlen;unsigned char out[4096];int outlen = 0;strcpy((char *)in, "aadddddddddddaaaaaaaaaaa");inlen = 9;CSocketProtocol *sp = NULL;//sp = new CSckFactoryImp1sp = new CSckFactoryImp2; //ret = SckSendAndRec01(sp, in, inlen, out, &outlen);if (ret != 0){printf("func SckSendAndRec() err:%d \n", ret);return ret;}delete sp; //想通過父類指針 釋放所有的子類對象的資源 ..cout<<"hello..."<<endl;system("pause");return ret;
}
5.加密協議抽象類的定義
#pragma onceclass CEncDesProtocol
{
public:CEncDesProtocol(){}virtual ~CEncDesProtocol(){}virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int *cryptlen) = 0;virtual int DecData(unsigned char *cryptdata, int cryptlen, unsigned char *plain, int *plainlen) = 0;};
6.廠商一的加密功能實現
- 類的頭文件
#include <iostream>
using namespace std;#include "CEncDesProtocol.h"class HwEncDec : public CEncDesProtocol
{
public:virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int *cryptlen);virtual int DecData(unsigned char *cryptdata, int cryptlen, unsigned char *plain, int *plainlen);
};
- 類的實現文件
#include <iostream>
using namespace std;
#include "HwEncDec.h"
#include "des.h"int HwEncDec::EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int *cryptlen)
{int ret = 0;//用戶使用的函數ret = DesEnc(plain,plainlen, cryptdata, cryptlen);if (ret != 0){printf("func DesEnc() err:%d \n ", ret);return ret;}return ret;
}int HwEncDec::DecData(unsigned char *cryptdata, int cryptlen, unsigned char *plain, int *plainlen)
{int ret = 0;//用戶使用函數des解密ret = DesDec(cryptdata, cryptlen, plain, plainlen);if (ret != 0){printf("func DesDec() err:%d \n ", ret);return ret;}return ret;
}
7.加密功能的測試文件
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;#include "CSocketProtocol.h"
#include "CSckFactoryImp1.h"
#include "CSckFactoryImp2.h"#include "CEncDesProtocol.h"
#include "HwEncDec.h"//面向抽象類編程,框架實現完畢
int SckSendAndRec(CSocketProtocol *sp, unsigned char *in, int inlen, unsigned char *out, int *outlen)
{int ret = 0;ret = sp->cltSocketInit();if (ret != 0){goto End;}ret = sp->cltSocketSend(in, inlen);if (ret != 0){goto End;}ret = sp->cltSocketRev(out, outlen);if (ret != 0){goto End;}End:ret = sp->cltSocketDestory();return 0;
}//面向抽象類編程,框架實現完畢
//c函數
int SckSendAndRec_EncDec(CSocketProtocol *sp, CEncDesProtocol *ed, unsigned char *in, int inlen, unsigned char *out, int *outlen)
{int ret = 0;unsigned char data[4096];int datalen = 0;ret = sp->cltSocketInit();if (ret != 0){goto End;}ret = ed->EncData(in,inlen, data, &datalen);if (ret != 0){goto End;}ret = sp->cltSocketSend(data, datalen); //發送數據之前對數據加密 ..if (ret != 0){goto End;}ret = sp->cltSocketRev(data, &datalen); //收到的數據是密文,需要進行解密if (ret != 0){goto End;}ret = ed->DecData(data, datalen, out, outlen );if (ret != 0){goto End;}End:ret = sp->cltSocketDestory();return 0;
}//寫一個框架
int main022()
{int ret = 0;unsigned char in[4096];int inlen;unsigned char out[4096];int outlen = 0;strcpy((char *)in, "aadddddddddddaaaaaaaaaaa");inlen = 9;CSocketProtocol *sp = NULL;CEncDesProtocol *ed = NULL;//sp = new CSckFactoryImp1sp = new CSckFactoryImp2; //ed = new HwEncDec;ret = SckSendAndRec_EncDec(sp, ed, in, inlen, out, &outlen);if (ret != 0){printf("func SckSendAndRec() err:%d \n", ret);return ret;}delete sp; //想通過父類指針 釋放所有的子類對象的資源 ..cout<<"hello..."<<endl;system("pause");return ret;
}
加解密的代碼是des.h和des.c,可在前面“08文件操作”查看源代碼。
8.將測試框架從函數形式升級為類的形式
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;#include "CSocketProtocol.h"
#include "CSckFactoryImp1.h"
#include "CSckFactoryImp2.h"#include "CEncDesProtocol.h"
#include "HwEncDec.h"//抽象類在多繼承中的應用
/*
class MainOp : public CSocketProtocol, public CEncDesProtocol
{
public:
protected:
private:};
*/class MainOp
{
public:MainOp(){this->sp = NULL;this->ed = NULL;}MainOp(CSocketProtocol *sp, CEncDesProtocol *ed){this->sp = sp;this->ed = ed;}//void setSp(CSocketProtocol *sp){this->sp = sp;}void setEd(CEncDesProtocol *ed){this->ed = ed;}public://面向抽象類編程,框架實現完畢int SckSendAndRec_EncDec3(CSocketProtocol *sp, CEncDesProtocol *ed, unsigned char *in, int inlen, unsigned char *out, int *outlen){int ret = 0;unsigned char data[4096];int datalen = 0;ret = sp->cltSocketInit();if (ret != 0){goto End;}ret = ed->EncData(in,inlen, data, &datalen);if (ret != 0){goto End;}ret = sp->cltSocketSend(data, datalen); //發送數據之前對數據加密 ..if (ret != 0){goto End;}ret = sp->cltSocketRev(data, &datalen); //收到的數據是密文,需要進行解密if (ret != 0){goto End;}ret = ed->DecData(data, datalen, out, outlen );if (ret != 0){goto End;}End:ret = sp->cltSocketDestory();return 0;}int SckSendAndRec_EncDec3(unsigned char *in, int inlen, unsigned char *out, int *outlen){int ret = 0;unsigned char data[4096];int datalen = 0;ret = this->sp->cltSocketInit();if (ret != 0){goto End;}ret = this->ed->EncData(in,inlen, data, &datalen);if (ret != 0){goto End;}ret = this->sp->cltSocketSend(data, datalen); //發送數據之前對數據加密 ..if (ret != 0){goto End;}ret = sp->cltSocketRev(data, &datalen); //收到的數據是密文,需要進行解密if (ret != 0){goto End;}ret = ed->DecData(data, datalen, out, outlen );if (ret != 0){goto End;}End:ret = sp->cltSocketDestory();return 0;}private:CSocketProtocol *sp;CEncDesProtocol *ed;};//寫一個框架
int main()
{int ret = 0;unsigned char in[4096];int inlen;unsigned char out[4096];int outlen = 0;strcpy((char *)in, "aadddddddddddaaaaaaaaaaa");inlen = 9;MainOp *myMainOp = new MainOp;CSocketProtocol *sp = NULL;CEncDesProtocol *ed = NULL;//sp = new CSckFactoryImp1sp = new CSckFactoryImp2; //ed = new HwEncDec;myMainOp->setSp(sp);myMainOp->setEd(ed);ret = myMainOp->SckSendAndRec_EncDec3(in, inlen, out, &outlen);if (ret!= 0){printf("myMainOp SckSendAndRec_EncDec3() err\n ", ret);}delete sp;delete ed;delete myMainOp;cout<<"hello..."<<endl;system("pause");return ret;
}
無非就是將之前的全局函數封裝在一個測試用的類里面,然后該測試類擁有socket和加解密協議的基類對象作為該測試類的成員變量。
6.C語言回調函數和函數指針
結論:回調函數的本質:提前做了一個協議的約定(把函數的參數、函數返回值提前約定)
動態庫升級為框架的編碼實現
1、 動態庫中定義協議,并完成任務的調用
typedef int (*EncData)(unsigned char *inData,int inDataLen,unsigned char *outData,int *outDataLen,void *Ref, int RefLen);
typedef int (*DecData)(unsigned char *inData,int inDataLen,unsigned char *outData,int *outDataLen,void *Ref, int RefLen);
2、 加密廠商完成協議函數的編寫
3、 對接調試。
4、 動態庫中可以緩存第三方函數的入口地址,也可以不緩存,兩種實現方式。
案例總結
回調函數:利用函數指針做函數參數,實現的一種調用機制,具體任務的實現者,可以不知道什么時候被調用。
回調機制原理:
- 當具體事件發生時,調用者通過函數指針調用具體函數
- 回調機制將調用者和被調函數分開,兩者互不依賴
- 任務的實現 和 任務的調用 可以耦合 (提前進行接口的封裝和設計)