C++复习:纯虚函数和抽象类

纯虚函数和抽象类

1基本概念

2抽象类案例

 

3抽象类在多继承中的应用

C++中没有Java中的接口概念,抽象类可以模拟Java中的接口类。(接口和协议)

3.1有关多继承的说明

工程上的多继承

被实际开发经验抛弃的多继承

工程开发中真正意义上的多继承是几乎不被使用的

多重继承带来的代码复杂性远多于其带来的便利

多重继承对代码维护性上的影响是灾难性的

在设计方法上,任何多继承都可以用单继承代替

多继承中的二义性和多继承不能解决的问题

3.2多继承的应用场景

C++中是否有Java中的接口概念?

绝大多数面向对象语言都不支持多继承

绝大多数面向对象语言都支持接口的概念

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;

 

/*

C++中没有接口的概念

C++中可以使用纯虚函数实现接口

接口类中只有函数原型定义,没有任何数据的定义。

*/

 

class Interface1

{

public:

    virtual void print() = 0;

    virtual int add(int a, int b) = 0;

};

 

class Interface2

{

public:

    virtual void print() = 0;

    virtual int add(int a, int b) = 0;

    virtual int minus(int a, int b) = 0;

};

 

class parent

{

public:

    int a;

};

class Child : public parent, public Interface1, public Interface2

{

public:

    void print()

    {

        cout << "Child::print" << endl;

    }

 

    int add(int a, int b)

    {

        return a + b;

    }

 

    int minus(int a, int b)

    {

        return a - b;

    }

};

 

int main()

{

    Child c;

 

    c.print();

 

    cout << c.add(3, 5) << endl;

    cout << c.minus(4, 6) << endl;

 

    Interface1* i1 = &c;

    Interface2* i2 = &c;

 

    cout << i1->add(7, 8) << endl;

    cout << i2->add(7, 8) << endl;

    system("pause");

}

4抽象类知识点强化

/*

编写一个C++程序, 计算程序员( programmer )工资

    1 要求能计算出初级程序员( junior_programmer ) 中级程序员 ( mid_programmer )高级程序员( adv_programmer)的工资

    2 要求利用抽象类统一界面,方便程序的扩展, 比如:新增, 计算 架构师 (architect ) 的工资

*/

5面向抽象类编程思想强化

理论知识

  • 虚函数和多态性使成员函数根据调用对象的类型产生不同的动作
  • 多态性特别适合于实现分层结构的软件系统,便于对问题抽象时 定义共性,实现时定义区别
  • 面向抽象类编程(面向接口编程)是项目开发中重要技能之一。

4.1案例: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 业务逻辑、数据、界面显示分离的方法

        面向对象思想扩展aopAOPOOP的延续)思想

            aop思想是对继承编程思想的有力的补充

4.2案例:计算员工工资

 

4.3案例:计算几何体的表面积和体积

 

 

6 C面向接口编程和C多态

结论:    只要你动手,又很容易!

6.1函数类型语法基础

函数三要素: 名称、参数、返回值

C语言中的函数有自己特定的类型

C语言中通过typedef为函数类型重命名

typedef type name(parameter list)

typedef int f(int, int);

typedef void p(int);

函数指针

函数指针用于指向一个函数

函数名是函数体的入口地址

1)可通过函数类型定义函数指针: FuncType* pointer;

2)也可以直接定义:type (*pointer)(parameter list);

pointer为函数指针变量名

type为指向函数的返回值类型

parameter list为指向函数的参数类型列表

函数指针语法梳理

//函数类型

//函数指针类型

//函数指针变量

 

数组指针语法梳理

//数组类型语法

//数组指针类型

//数组指针变量

 

typedef int(FUNC)(int);

 

int test(int i)

{

    return i * i;

}

 

void f()

{

    printf("Call f()...\n");

}

 

int main()

{

    FUNC* pt = test;

 

    void(*pf)() = &f;

 

    pf();

    (*pf)();

 

    printf("Function pointer call: %d\n", pt(3));

}

6.2函数指针做函数参数

  1. 指针做函数参数pk函数指针做函数参数

    回忆指针做函数参数

一级指针做函数参数、二级。。。。、三级

  1. 函数指针做函数参数

当函数指针 做为函数的参数,传递给一个被调用函数,

被调用函数就可以通过这个指针调用外部的函数,这就形成了回调

3、练习

int add(int a, int b);

int libfun(int(*pDis)(int a, int b));

 

int main(void)

{

    int(*pfun)(int a, int b);

    pfun = add;

    libfun(pfun);

 

}

 

int add(int a, int b)

{

    return a + b;

 

}

 

int libfun(int(*pDis)(int a, int b))

{

    int a, b;

    a = 1;

    b = 2;

    add(1, 3) //直接调用add函数

        printf("%d", pDis(a, b)); //通过函数指针做函数参数,间接调用add函数

                                 //思考 这样写 pDis(a, b)有什么好处?

}

//剖析思路

//1函数的调用 和 函数的实现 有效的分离

//2 C++的多态,可扩展

 

现在这几个函数是在同一个文件当中

假如

int libfun(int(*pDis)(int a, int b))

是一个库中的函数,就只有使用回调了,通过函数指针参数将外部函数地址传入

来实现调用

 

函数 add 的代码作了修改,也不必改动库的代码,就可以正常实现调用

便于程序的维护和升级

 

回调函数思想:

结论:回调函数的本质:提前做了一个协议的约定(把函数的参数、函数返回值提前约定)

请思考:C编译器通过那个具体的语法,实现解耦合的?

    C++编译器通过多态的机制(提前布局vptr指针和虚函数表,找虚函数入口地址来实现)

6.3函数指针正向调用

  1. 函数指针做函数参数,调用方式

    被调用函数和主调函数在同一文件中(用来教学,没有任何意义)

2、函数指针做函数参数

被调用函数和主调函数不在同一个文件中、模块中。

难点:理解被调用函数是什么机制被调用起来的。框架

框架提前设置了被调用函数的入口(框架提供了第三方模块入口地址的集成功能)

框架具备调用第三方模块入口函数

1、    练习

 

typedef int(*EncDataFunc)(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen);

 

int MyEncDataFunc(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen)

{

    int rv = 0;

    char *p = "222222222222";

 

    strcpy(outData, p);

    *outDataLen = strlen(p);

    return rv;

}

 

int Send_Data(EncDataFunc encDataFunc, unsigned char *inData, int inDataLen, unsigned char *outData, int *outDatalen)

{

    int rv = 0;

    if (encDataFunc != NULL)

    {

        rv = encDataFunc(inData, inDataLen, outData, outDatalen, NULL, 0);

        if (rv != 0)

        {

            printf("func encDataFunc() err.\n");

            return rv;

        }

    }

    return rv;

}

 

int main()

{

    int rv = 0;

 

    EncDataFunc encDataFunc = NULL;

    encDataFunc = MyEncDataFunc;

 

    // 第一个调用

    {

        unsigned char inData[2048];

        int inDataLen;

        unsigned char outData[2048];

        int outDatalen;

        strcpy(inData, "1111");

        inDataLen = strlen(inData);

        rv = encDataFunc(inData, inDataLen, outData, &outDatalen, NULL, 0);

        if (rv != 0)

        {

            printf("edf err .....\n");

        }

        else

        {

            printf("edf ok \n");

            printf("%s \n", outData);

        }

    }

 

    {

        unsigned char inData[2048];

        int inDataLen;

        unsigned char outData[2048];

        int outDatalen;

        strcpy(inData, "3333");

        inDataLen = strlen(inData);

        rv = Send_Data(MyEncDataFunc, inData, inDataLen, outData, &outDatalen);

        if (rv != 0)

        {

            printf("func Send_Data err:%d", rv);

            return rv;

        }

        printf("%s \n", outData);

    }

 

    getchar();

}

6.4函数指针反向调用

回调函数效果展示。

6.C动态库升级成框架案例

C语言版本Socket动态库升级成框架集成第三方产品

简称:C动态库升级成框架案例

名字解释    

    动态库:抽象类一个套接口,单独封装成模块,供别人调用;无法扩展。

    框架:能自由的扩展

 

案例背景:一般的企业信息系统都有成熟的框架,可以有C语言写,也可以由C++语言。软件框架一般不发生变化,能自由的集成第三方厂商的产品。

 

案例需求:在socket通信库中,完成数据加密功能,有n个厂商的加密产品供你选择,如何实现动态库和第三个厂商产品的解耦合。

提醒:C++通过抽象类,也就是面向抽象类编程实现的(相当于C++编译器通过多态机制,已经很好用了。提前布局vptr指针、虚函数表;调用是迟绑定完成。),

C语言中如何实现哪?

 

案例要求:    1)能支持多个第三方厂商加密产品的入围

        2)企业信息系统框架不轻易发生框架

 

需求实现思路分析

    思考1:企业信息系统框架、第三方产品如何分层

思考2:企业信息系统框架,如何自由集成第三方产品

(软件设计:模块要求松、接口要求紧)

    思考3:软件分层确定后,动态库应该做什么?产品入围厂商应该做什么?

以后,开发企业信息系统框架的程序员,应该做什么?

                第三方产品入围应该做什么?

编码实现

        

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

案例总结

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

    回调机制原理:

        当具体事件发生时,调用者通过函数指针调用具体函数

        回调机制的将调用者和被调函数分开,两者互不依赖

        任务的实现 和 任务的调用 可以耦合 (提前进行接口的封装和设计)

6.6附录:诸葛亮的锦囊妙计

刘备利用周瑜、曹仁厮杀之际,乘虚袭取了南郡、荆州、襄阳,以后又征服了长沙等四郡。周瑜想想十分气恨,正无处报复以夺还荆州。不久,刘备忽然丧偶,周瑜计上心来,对孙权说:"您的妹妹,美丽、刚强,我们以联姻抗曹名义向刘备招亲,把他骗来南徐幽禁,逼他们拿荆州来换。"孙权大喜,郎派人到荆州说亲。

刘备认为这是骗局,想要拒绝,诸葛亮笑道:"送个好妻子上门何不答应?您只管去东吴,我叫赵云陪您去,自有安排,包您得了夫人又不失荆州。"

接着,诸葛亮暗暗关照赵云道:"我这里有三个锦囊,内藏三条妙计。到南徐时打开第一个,到年底时打开第二个,危急无路时打开第三个。"

第一个锦囊

    一到东吴就拜会乔国老

第二个锦囊

    刘备被孙权设计留下就对他谎称曹操大军压境

第三个锦囊

被东吴军队追赶就求孙夫人解围

转载于:https://www.cnblogs.com/love-DanDan/p/8976027.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值