纯虚函数和抽象类

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

        面向对象思想扩展aop(AOP是OOP的延续)思想

            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附录:诸葛亮的锦囊妙计

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

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

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

第一个锦囊

    一到东吴就拜会乔国老

第二个锦囊

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

第三个锦囊

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

C++复习:纯虚函数和抽象类的更多相关文章

  1. C++基础 (7) 第七天 多态的原理 纯虚函数和抽象类 依赖倒置原则

    1 昨日回顾 2 多态的原理 1 要有继承 2 要有子类重写父类的虚函数 3 父类指针(或者引用)指向子类对象 (动态联编 虚函数表 3 证明vptr指针的存在 4 vptr指针在构造父类的时候是分步 ...

  2. C++学习基础十二——纯虚函数与抽象类

    一.C++中纯虚函数与抽象类: 1.含有一个或多个纯虚函数的类成为抽象类,注意此处是纯虚函数,而不是虚函数. 2.如果一个子类继承抽象类,则必须实现父类中的纯虚函数,否则该类也为抽象类. 3.如果一个 ...

  3. C++基础(纯虚函数与抽象类)

    C++基础之纯虚函数与抽象类 引言 纯虚函数在C++编程中的地位很重要,其关联到了设计模式中"接口"的概念. 语法 纯虚函数的语法: 1.  将成员函数声明为virtual 2.  ...

  4. C++:纯虚函数与抽象类

    5.4.3 纯虚函数和抽象类 纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但是要求在派生类中根据需要对它进行定义,或仍然说明为纯虚函数. 声明纯虚函数的一般格式是: virtual 函数 ...

  5. c++,纯虚函数与抽象类

    1.纯虚函数的定义: (1)虚函数被“初始化”为0的函数.声明纯虚函数的一般形式是virtual 函数类型 函数名(参数表列) =0;(2)纯虚函数没有函数体:(3)最后面的“=0”并不表示函数返回值 ...

  6. 简单地说, cpp中的纯虚函数就是抽象类的具体实现

    简单地说, cpp中的纯虚函数就是抽象类的具体实现.包含了纯虚函数的类就是抽象类.

  7. c++-纯虚函数和抽象类

    纯虚函数和抽象类 C面向接口编程和C多态 函数类型语法基础 函数指针做函数参数(回调函数)思想剖析 函数指针做函数参数两种用法(正向调用.反向调用) 纯虚函数 抽象类 抽象类基本概念 抽象类在多继承中 ...

  8. C++开发系列-纯虚函数和抽象类

    概念 纯虚函数和抽象类 纯虚函数是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都实现该函数. 纯虚函数为各派生类提供了一个公共界面(接口的封装和设计.软件的模块功能的划分) 纯虚函数说明 ...

  9. cc32b_demo-32dk2j_cpp_纯虚函数与抽象类2-txwtech

    cc32b_demo-32dk2j_cpp_纯虚函数与抽象类2-txwtech //纯虚函数是用来继承用的//纯虚函数//抽象类-抽象数据类型//*任何包含一个或者多个纯虚函数的类都是抽象类//*不要 ...

随机推荐

  1. Course List for Student

    题目描述 Zhejiang University has 40000 students and provides 2500 courses. Now given the student name li ...

  2. U3D学习11——nav导航和动画

    一.nav导航 1.nav mesh agent 2.off mesh link 3.navigation面板-areas标签的应用,导航分层 二.动画 1.avatar可重用. 2.Animator ...

  3. EventBus的使用;消息传递之EventBus;

    EventBus传递消息(数据)和广播有点像,对广播传递数据有兴趣的可以看一下:Android数据传递,使用广播BroadcastReceiver: 1.添加build.gradle implemen ...

  4. JQ获取地址栏参数

    //获取地址栏参数 function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + " ...

  5. 输入框占位符placeholder

    占位符placeholder的益处不用多说,但是很不幸的是,在IE8之前的浏览器里是无法实现placeholder这一属性的,所以在需要兼容IE8之前的浏览器的情况下,我们不得不想办法模拟实现plac ...

  6. 【Selenium-WebDriver自学】Selenium网格化(十六)

    参考链接: http://www.yiibai.com/selenium/selenium_grids.html 命令: cd E:\Yingpu\000.SVNYP\01.个人文件夹\Renqian ...

  7. mysql中的sql_mode

    mysql数据库的中有一个环境变量sql_mode,定义了mysql应该支持的sql语法,数据校验等!我们可以通过以下方式查看当前数据库使用的sql_mode: mysql> select @@ ...

  8. thinkphp 验证的使用

    TP5验证可分为独立验证和验证器: 独立验证是可直接写在控制器里直接验证如下: //独立验证 $data = [ 'name'=>'vendor33333', 'email'=>'vaen ...

  9. File Input Features

    文件输入功能 1.该插件将将一个简单的 HTML 文件输入转换为高级文件选取器控件.将有助于对不支持 JQuery 或 Javascript 的浏览器的正常 HTML 文件输入进行回退. 2.文件输入 ...

  10. 禁用firefox 56自动更新

    firefox 56支持旧式扩展,这很重要! 它却自动更新,简单地关了也不行,很是牛氓! ========== -备份C:\Users\用户名\AppData\Roaming\Mozilla\Fire ...