19纯虚函数和抽象类

纯虚函数和抽象类

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  once

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

案例总结

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

  • 回调机制原理:

    • 当具体事件发生时,调用者通过函数指针调用具体函数
    • 回调机制将调用者和被调函数分开,两者互不依赖
    • 任务的实现 和 任务的调用 可以耦合 (提前进行接口的封装和设计)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值