1. 程式人生 > >c++ 純虛擬函式和抽象類

c++ 純虛擬函式和抽象類

一 基本概念
1 純虛擬函式是一個在類中宣告的虛擬函式,在類中沒有定義實體,要求各派生類定義自己的版本。
2 純虛擬函式為各派生類提供一個公共介面(介面的封裝設計、軟體的模組功能劃分);
3 語法:virtual 型別 函式名(引數)=0;
4 一個具有純虛擬函式的類成為抽象類。

#include <iostream>
using namespace std;

class  Figure //抽象類
{
public:
virtual void getArea() = 0 ; //純虛擬函式
};

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 main()
{
//Figure f; //抽象類不能被例項化
Figure *base = NULL; //抽象類不能被例項化

Circle c1(10, 20);
Tri t1(20, 30);
Square s1(50, 60);

objplay(&c1);
objplay(&t1);
objplay(&s1);

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;
}
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;
}
};

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 ;
}

三 知識點強化案例
1 要求能計算出初級程式設計師( junior_programmer ) 中級程式設計師 ( mid_programmer )高階程式設計師( adv_programmer)的工資
2 要求利用抽象類統一介面,方便程式的擴充套件, 比如:新增, 計算 架構師 (architect ) 的工資

四面向抽象類程式設計思想強化
1 面向抽象類程式設計(面向介面程式設計)是專案開發中重要技能之一。
2 案例: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++類方式,框架類)

#include<iostream>
#include<string.h>

using namespace std;
class cSocketProtocal
{
public:
cSocketProtocal(){}
virtual ~cSocketProtocal(){}
virtual int cSockInit() = 0;
virtual int cSockSend(const unsigned char *buf, const int buflen) = 0;
virtual int cSockRecv(unsigned char *buf, int *buflen) = 0;
};

class CSckFactoryImp1 :public cSocketProtocal
{
public :
CSckFactoryImp1(){}
~CSckFactoryImp1(){}
virtual int cSockInit();
virtual int cSockSend(const  unsigned char *buf, const int buflen);
virtual int cSockRecv(unsigned char *buf, int *buflen);

private:
unsigned char *p;
int len;
};

int CSckFactoryImp1::cSockInit()
{
p = NULL;
len = 0;
return 0;
}

int CSckFactoryImp1::cSockSend(const unsigned char *buf, const int buflen)
{
p = (unsigned char*)malloc(sizeof(unsigned char)* buflen);
if (p == NULL)
    return -1;
memcpy(p, buf, buflen);
len = buflen;
return 0;
}

int CSckFactoryImp1::cSockRecv(unsigned char *buf, int *buflen)
{
if (buf == NULL || buflen  == 0)
    return -1;
*buflen = this->len;
memcpy(buf, p, len);

return 0;
}
/*加密*/
class CEncDesProtocol
{
public:
CEncDesProtocol(){}
virtual ~CEncDesProtocol(){}
virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int * crytlen) = 0;
virtual int DecData(unsigned char * cryptdata, int crytlen, unsigned char * plain, int * plainlen) = 0;
};

class HWEncDec:public CEncDesProtocol
{
public:
HWEncDec(){}
~HWEncDec(){}
virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int * crytlen);
virtual int DecData(unsigned char * cryptdata, int crytlen, unsigned char * plain, int * plainlen);
};

int HWEncDec::EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int * crytlen)
{
return 0;
}
int HWEncDec::DecData(unsigned char * cryptdata, int crytlen, unsigned char * plain, int * plainlen)
{
return 0;
}

/*框架類*/
class MainOp
{
public:
MainOp(){ this->sp = NULL; this->ed = NULL; }
MainOp(cSocketProtocal *sp, CEncDesProtocol *ed)
{
    this->sp = sp;
    this->ed = ed;
}
    ~MainOp(){}

int SckSendAndRec(const unsigned char *in, const int inlen, unsigned char*  out, int *outlen);

private:
cSocketProtocal *sp;
CEncDesProtocol *ed;
};
int MainOp::SckSendAndRec(const unsigned char *in, const int inlen, unsigned char*  out, int *outlen)
{
this->sp->cSockInit();
this->sp->cSockSend(in, inlen);
this->sp->cSockRecv(out,outlen);
return 0;
}
int main()
{
cSocketProtocal *sp = new CSckFactoryImp1;
CEncDesProtocol *ed = new HWEncDec;
const unsigned char in[100] = "123214";
const int inlen = 10;
unsigned char out[100];
int outlen = 0;
MainOp *myMainOp = new MainOp(sp,ed);
int ret = myMainOp->SckSendAndRec(in, inlen, out, &outlen);
return 1;
}

五 C面向介面程式設計和C多型
1 C函式指標

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

//函式指標語法梳理
//1 如何定義一個函式型別
//2 如何定義一個函式指標型別
//3 如何定義一個 函式指標  (指向一個函式的入口地址)

int add(int a, int b)
{
printf("func add ....\n");
return a +b;
}
void main()
{
add(1, 2); //直接呼叫呼叫 //函式名就是函式的入口地址 

//定義一個函式型別
{
    typedef int (MyFuncType)(int a, int b); //定義了一個型別
    MyFuncType *myPointerFunc = NULL; //定義了一個指標, 指向某一種類的函式..
    myPointerFunc  = &add;  //細節
    myPointerFunc(3, 4); //間接呼叫
    myPointerFunc  = add;  //細節 //C 過程 相容歷史版本的原因
    myPointerFunc(3, 4); //間接呼叫
}

//定義一個函式指標型別
{
    typedef int (*MyPointerFuncType)(int a, int b); //int * a = NULL;
    MyPointerFuncType myPonterFunc; //定義一個指標
    myPonterFunc = add;
    myPonterFunc(5, 6);
}
//函式指標 
{
    int (*MyPonterFunc)(int a, int b); //定義了一個變數
    MyPonterFunc = add;
    MyPonterFunc(7, 8);
}
system("pause");
}

2 函式指標做引數思想剖析
結論:回撥函式的本質:提前做了一個協議的約定(把函式的引數、函式返回值提前約定)
請思考:C編譯器通過哪個具體的語法,實現解耦合的?函式指標
C++編譯器通過多型的機制(提前佈局vptr指標和虛擬函式表,找虛擬函式入口地址來實現)

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int myadd(int a, int b)  //子任務的實現者
{
printf("func add() do...\n");
return a + b;
}
int myadd2(int a, int b)  //子任務的實現者
{
printf("func add2() do...\n");
return a + b;
}
int myadd3(int a, int b)  //子任務的實現者
{
printf("func add3() do...\n");
return a + b;
}
int myadd4(int a, int b)  //子任務的實現者
{
printf("func add4() do...\n");
return a + b;
}

//定義了一個型別 
typedef int (*MyTypeFuncAdd)(int a, int b);

//函式指標 做 函式引數
int MainOp(MyTypeFuncAdd myFuncAdd)
{
int c = myFuncAdd(5, 6);
return c;
}

// int (*MyPointerFuncAdd)(int a, int b)
int MainOp2(int (*MyPointerFuncAdd)(int a, int b) )
{
int c = MyPointerFuncAdd(5, 6); //間接呼叫
return c;
}

//任務的呼叫 和 任務的編寫可以分開
void main()
{
//在mainop框架 沒有發生任何變化的情況下 ...
MainOp(myadd2);
MainOp(myadd3);
MainOp(myadd4);

printf("hello...\n");
system("pause");
return ;
}

3 函式指標正向呼叫
逐步找到函式入口地址,呼叫函式。。

4函式指標反向呼叫
1提前定義好一套介面(函式指標型別的定義)
2 在外部發布一套介面協議(.h)
3 廠商根據.h實現函式原型(編寫子任務)
4 把廠商的函式的入口地址注入到框架中
5 在框架中回掉第三方的任務

案例

#include <stdio.h>
#include<stdlib.h>     

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

/* 函式指標 */
typedef int (*fcb_func)(int a, int b);

typedef struct mydata {
int a, b; 
fcb_func fcb; /* 函式管理器 */
} mydata_t;

/* 建立時傳入相應的函式管理器 */
mydata_t* mydata_create(fcb_func out_fcb)
{
mydata_t *data = (mydata_t *)malloc(sizeof(mydata_t));
data->fcb = out_fcb;
data->a = 0;
data->b = 0;
return data;
}
void mydata_release(mydata_t* data)
{
    free(data);
}

void mydata_operate(mydata *data)
{
int c = data->fcb(data->a, data->b);
printf("mydata inner operate %d\n", c);
}

int main()
{
mydata_t *data = mydata_create(add); 
data->a = 10;
data->b = 3;

mydata_operate(data);

data->fcb = sub ; /* 改變函式管理器 */
mydata_operate(data);

mydata_release(data);
return 0;
}