纯虚函数和抽象类

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. [UE4]使用材质将图片变成黑白

    拖动到材质界面不放,会自动切换到材质界面: 拖放到视图窗口,放开鼠标,就会自动生成一个“Texture Sample”节点 图片材质使用方法跟直接使用图片素材一样:

  2. SCCM 2012 R2实战系列之八:OSD(上)--分发全新Windows7系统

    今天将跟大家一起分享SCCM 中最为重要的一个功能---操作系统分发(OSD),在此文章中会讨论到OSD的初始化配置.镜像的导入.任务序列的创建编辑.并解决大家经常遇到的分发windows7系统分区盘 ...

  3. iOS @property语句

    @property声明的形式是: @property ( attributes ) type name; type和name的含义一目了然,attributes描述了如何编写访问器. 一.assign ...

  4. Android短信收发(二)

    接收SMS类,代码如下 //for receive SMS private SmsReceiver mSmsReceiver; @Override protected void onResume() ...

  5. (转)C#操作Word文档

    原文1地址:http://www.cnblogs.com/lantionzy/archive/2009/10/23/1588511.html 原文2地址: http://www.cnblogs.com ...

  6. mapreduce运行原理及YARN

    mapreduce1回顾 mapreduce1的不足 yarn的基本架构 yarn工作流程

  7. AndroidStudio查看无用的资源文件;

    1.打开需要查看的项目,选择AS上方标题栏的Analyze选项: 2.选择 Run Inspection by Name 3.在弹出框内输入 unused resources 4.筛选你需要查看的资源 ...

  8. call与apply简单介绍

    var pet={ word:'...', speak:function(say){ console.log(say+' '+this.word) } } //pet.speak('speak')// ...

  9. fiddler--配置火狐代理配置代理

    fiddler安装 下载fiddler最新版: 默认安装: 配置火狐代理配置代理 打开fiddler 按图操作,复制选中的链接:fiddler -> tool ->connections ...

  10. Python strip lstrip rstrip使用方法(字符串处理空格)

    Python strip lstrip rstrip使用方法(字符串处理空格)   strip是trim掉字符串两边的空格.lstrip, trim掉左边的空格rstrip, trim掉右边的空格 s ...