c++ 纯虚函数和抽象类

一 基本概念
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;
}

猜你喜欢

转载自blog.csdn.net/weixin_40878579/article/details/81368295