19纯虚函数和抽象类

来源:互联网 发布:双十一 淘宝 消费人群 编辑:程序博客网 时间:2024/06/01 08:50

纯虚函数和抽象类

  • 纯虚函数和抽象类
    • 基本概念
    • 案例
    • 抽象类在多继承中的应用
    • 面向抽象类编程
    • socket库c模型设计和实现
    • C语言回调函数和函数指针

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思想是对继承编程思想的有力的补充

实现步骤

  1. 定义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 CSckFactoryImp1    sp = 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 CSckFactoryImp1    sp = 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 CSckFactoryImp1    sp = 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、 动态库中可以缓存第三方函数的入口地址,也可以不缓存,两种实现方式。

案例总结

  • 回调函数:利用函数指针做函数参数,实现的一种调用机制,具体任务的实现者,可以不知道什么时候被调用。

  • 回调机制原理:

    • 当具体事件发生时,调用者通过函数指针调用具体函数
    • 回调机制将调用者和被调函数分开,两者互不依赖
    • 任务的实现 和 任务的调用 可以耦合 (提前进行接口的封装和设计)
原创粉丝点击