一 基本概念
1 纯虚函数是一个在类中声明的虚函数,在类中没有定义实体,要求各派生类定义自己的版本。
2 纯虚函数为各派生类提供一个公共界面(接口的封装设计、软件的模块功能划分);
3 语法:virtual 类型 函数名(参数)=0;
4 一个具有纯虚函数的类成为抽象类。
#include <iostream>
using namespace std;
class Figure //抽象类
{
public:
virtual void getArea() = 0 ; //纯虚函数
};
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 main()
{
//Figure f; //抽象类不能被实例化
Figure *base = NULL; //抽象类不能被实例化
Circle c1(10, 20);
Tri t1(20, 30);
Square s1(50, 60);
objplay(&c1);
objplay(&t1);
objplay(&s1);
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;
}
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;
}
};
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 ;
}
三 知识点强化案例
1 要求能计算出初级程序员( junior_programmer ) 中级程序员 ( mid_programmer )高级程序员( adv_programmer)的工资
2 要求利用抽象类统一界面,方便程序的扩展, 比如:新增, 计算 架构师 (architect ) 的工资
四面向抽象类编程思想强化
1 面向抽象类编程(面向接口编程)是项目开发中重要技能之一。
2 案例: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++类方式,框架类)
#include<iostream>
#include<string.h>
using namespace std;
class cSocketProtocal
{
public:
cSocketProtocal(){}
virtual ~cSocketProtocal(){}
virtual int cSockInit() = 0;
virtual int cSockSend(const unsigned char *buf, const int buflen) = 0;
virtual int cSockRecv(unsigned char *buf, int *buflen) = 0;
};
class CSckFactoryImp1 :public cSocketProtocal
{
public :
CSckFactoryImp1(){}
~CSckFactoryImp1(){}
virtual int cSockInit();
virtual int cSockSend(const unsigned char *buf, const int buflen);
virtual int cSockRecv(unsigned char *buf, int *buflen);
private:
unsigned char *p;
int len;
};
int CSckFactoryImp1::cSockInit()
{
p = NULL;
len = 0;
return 0;
}
int CSckFactoryImp1::cSockSend(const unsigned char *buf, const int buflen)
{
p = (unsigned char*)malloc(sizeof(unsigned char)* buflen);
if (p == NULL)
return -1;
memcpy(p, buf, buflen);
len = buflen;
return 0;
}
int CSckFactoryImp1::cSockRecv(unsigned char *buf, int *buflen)
{
if (buf == NULL || buflen == 0)
return -1;
*buflen = this->len;
memcpy(buf, p, len);
return 0;
}
/*加密*/
class CEncDesProtocol
{
public:
CEncDesProtocol(){}
virtual ~CEncDesProtocol(){}
virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int * crytlen) = 0;
virtual int DecData(unsigned char * cryptdata, int crytlen, unsigned char * plain, int * plainlen) = 0;
};
class HWEncDec:public CEncDesProtocol
{
public:
HWEncDec(){}
~HWEncDec(){}
virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int * crytlen);
virtual int DecData(unsigned char * cryptdata, int crytlen, unsigned char * plain, int * plainlen);
};
int HWEncDec::EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int * crytlen)
{
return 0;
}
int HWEncDec::DecData(unsigned char * cryptdata, int crytlen, unsigned char * plain, int * plainlen)
{
return 0;
}
/*框架类*/
class MainOp
{
public:
MainOp(){ this->sp = NULL; this->ed = NULL; }
MainOp(cSocketProtocal *sp, CEncDesProtocol *ed)
{
this->sp = sp;
this->ed = ed;
}
~MainOp(){}
int SckSendAndRec(const unsigned char *in, const int inlen, unsigned char* out, int *outlen);
private:
cSocketProtocal *sp;
CEncDesProtocol *ed;
};
int MainOp::SckSendAndRec(const unsigned char *in, const int inlen, unsigned char* out, int *outlen)
{
this->sp->cSockInit();
this->sp->cSockSend(in, inlen);
this->sp->cSockRecv(out,outlen);
return 0;
}
int main()
{
cSocketProtocal *sp = new CSckFactoryImp1;
CEncDesProtocol *ed = new HWEncDec;
const unsigned char in[100] = "123214";
const int inlen = 10;
unsigned char out[100];
int outlen = 0;
MainOp *myMainOp = new MainOp(sp,ed);
int ret = myMainOp->SckSendAndRec(in, inlen, out, &outlen);
return 1;
}
五 C面向接口编程和C多态
1 C函数指针
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//函数指针语法梳理
//1 如何定义一个函数类型
//2 如何定义一个函数指针类型
//3 如何定义一个 函数指针 (指向一个函数的入口地址)
int add(int a, int b)
{
printf("func add ....\n");
return a +b;
}
void main()
{
add(1, 2); //直接调用调用 //函数名就是函数的入口地址
//定义一个函数类型
{
typedef int (MyFuncType)(int a, int b); //定义了一个类型
MyFuncType *myPointerFunc = NULL; //定义了一个指针, 指向某一种类的函数..
myPointerFunc = &add; //细节
myPointerFunc(3, 4); //间接调用
myPointerFunc = add; //细节 //C 过程 兼容历史版本的原因
myPointerFunc(3, 4); //间接调用
}
//定义一个函数指针类型
{
typedef int (*MyPointerFuncType)(int a, int b); //int * a = NULL;
MyPointerFuncType myPonterFunc; //定义一个指针
myPonterFunc = add;
myPonterFunc(5, 6);
}
//函数指针
{
int (*MyPonterFunc)(int a, int b); //定义了一个变量
MyPonterFunc = add;
MyPonterFunc(7, 8);
}
system("pause");
}
2 函数指针做参数思想剖析
结论:回调函数的本质:提前做了一个协议的约定(把函数的参数、函数返回值提前约定)
请思考:C编译器通过哪个具体的语法,实现解耦合的?函数指针
C++编译器通过多态的机制(提前布局vptr指针和虚函数表,找虚函数入口地址来实现)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int myadd(int a, int b) //子任务的实现者
{
printf("func add() do...\n");
return a + b;
}
int myadd2(int a, int b) //子任务的实现者
{
printf("func add2() do...\n");
return a + b;
}
int myadd3(int a, int b) //子任务的实现者
{
printf("func add3() do...\n");
return a + b;
}
int myadd4(int a, int b) //子任务的实现者
{
printf("func add4() do...\n");
return a + b;
}
//定义了一个类型
typedef int (*MyTypeFuncAdd)(int a, int b);
//函数指针 做 函数参数
int MainOp(MyTypeFuncAdd myFuncAdd)
{
int c = myFuncAdd(5, 6);
return c;
}
// int (*MyPointerFuncAdd)(int a, int b)
int MainOp2(int (*MyPointerFuncAdd)(int a, int b) )
{
int c = MyPointerFuncAdd(5, 6); //间接调用
return c;
}
//任务的调用 和 任务的编写可以分开
void main()
{
//在mainop框架 没有发生任何变化的情况下 ...
MainOp(myadd2);
MainOp(myadd3);
MainOp(myadd4);
printf("hello...\n");
system("pause");
return ;
}
3 函数指针正向调用
逐步找到函数入口地址,调用函数。。
4函数指针反向调用
1提前定义好一套接口(函数指针类型的定义)
2 在外部发布一套接口协议(.h)
3 厂商根据.h实现函数原型(编写子任务)
4 把厂商的函数的入口地址注入到框架中
5 在框架中回掉第三方的任务
案例
#include <stdio.h>
#include<stdlib.h>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
/* 函数指针 */
typedef int (*fcb_func)(int a, int b);
typedef struct mydata {
int a, b;
fcb_func fcb; /* 函数管理器 */
} mydata_t;
/* 创建时传入相应的函数管理器 */
mydata_t* mydata_create(fcb_func out_fcb)
{
mydata_t *data = (mydata_t *)malloc(sizeof(mydata_t));
data->fcb = out_fcb;
data->a = 0;
data->b = 0;
return data;
}
void mydata_release(mydata_t* data)
{
free(data);
}
void mydata_operate(mydata *data)
{
int c = data->fcb(data->a, data->b);
printf("mydata inner operate %d\n", c);
}
int main()
{
mydata_t *data = mydata_create(add);
data->a = 10;
data->b = 3;
mydata_operate(data);
data->fcb = sub ; /* 改变函数管理器 */
mydata_operate(data);
mydata_release(data);
return 0;
}