标签:this Once 指针变量 名称 利用 子类 方式 自己的 base
(1)纯虚函数
纯虚函数是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都定义自己的版本;
纯虚函数位各派生类提供一个公共界面(接口的封装和设计、软件的模块功能划分);
(2)抽象类
一个具有纯虚函数的基类成为抽象类
// 抽象类
class Base
{
public:
virtual void fun1() = 0; // 纯虚函数
virtual void fun2() = 0;
};
void main()
{
//Base b; // err,抽象类不能实例化
Base* p;
}
定义抽象类 Figure,纯虚函数 get_area 提供接口,由各个派生类自己实现函数的功能
// 抽象类 figure图形
class Figure
{
public:
// 纯虚函数
virtual void get_area() = 0; // 求面积
};
class Circle : public Figure
{
public:
Circle(int r, int b)
{
this->r = r;
this->b = b;
}
virtual void get_area()
{
cout << "Circle area: " << 3.14*r*r << endl;
}
private:
int r;
int b;
};
class Triangle : public Figure
{
public:
Triangle(int h, int d)
{
this->h = h;
this->d = d;
}
virtual void get_area()
{
cout << "Triangle area: " << d*h/2 << endl;
}
private:
int h;
int d;
};
class Square : public Figure
{
public:
Square(int h, int d)
{
this->h = h;
this->d = d;
}
virtual void get_area()
{
cout << "Square area: " << d*h<< endl;
}
private:
int h;
int d;
};
void area(Figure* p)
{
p->get_area(); //多态
}
void main()
{
Figure* pF = NULL;
Circle c(10, 0);
Triangle t(20, 30);
Square s(40, 50);
// 通过父类指针指向子类对象
area(&c);
area(&t);
area(&s);
system("pause");
}
C++中没有 Java 中的接口概念,抽象类可以模拟 Java 中的接口类。
多继承的应用场景:继承多个接口类(纯虚函数实现接口)
C++中可以使用纯虚函数实现接口;接口类中只有函数原型定义,没有任何数据的定义。
多重继承接口不会带来二义性和复杂性等问题;
接口类只是一个功能说明,而不是功能实现。
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 test : public Interface1, public Interface2
{
public:
virtual void print()
{
cout << "test: print()已经执行\n";
}
virtual int add(int a, int b)
{
cout << "test: add()已经执行\n";
return a + b;
}
virtual int mult(int a, int b)
{
cout << "test: mult()已经执行\n";
return a*b;
}
};
void main()
{
test c1;
c1.print(); // 执行的是 test 中实现的功能,不存在二义性
Interface1 *it1 = &c1;
it1->add(1, 2);
Interface2 *it2 = &c1;
it2->mult(3, 4);
system("pause");
return;
}
编写一个程序,计算程序员( programmer )工资
(1)要求计算初级程序员(junior_programmer)中级程序员(mid_programmer)高级程序员(adv_programmer)的工资
(2)要求利用抽象类统一界面,方便程序的扩展
// 抽象类 programmer
class programmer
{
public:
// 纯虚函数
virtual void get_salary() = 0;
};
//初级程序员
class junior_programmer : public programmer
{
public:
junior_programmer(char *name, char *job, int sal)
{
this->name = name;
this->job = job;
this->sal = sal;
}
virtual void get_salary()
{
cout << name << " " << job << " : " << sal << endl;
}
private:
char *name;
char *job;
int sal;
};
//中级程序员
class mid_programmer : public programmer
{
public:
mid_programmer(char *name, char *job, int sal)
{
this->name = name;
this->job = job;
this->sal = sal;
}
virtual void get_salary()
{
cout << name << " " << job << " : " << sal << endl;
}
private:
char *name;
char *job;
int sal;
};
//高级程序员
class adv_programmer : public programmer
{
public:
adv_programmer(char *name, char *job, int sal)
{
this->name = name;
this->job = job;
this->sal = sal;
}
virtual void get_salary()
{
cout << name << " " << job << " : " << sal << endl;
}
private:
char *name;
char *job;
int sal;
};
//计算函数 简单的框架
void CalProgSal(programmer *base)
{
base->get_salary();
}
void main()
{
// 初始化
junior_programmer jp("张三", "初级工程师", 3000);
mid_programmer mp("李四", "中级工程师", 8000);
adv_programmer ap("王五", "高级工程师", 10000);
CalProgSal(&jp);
CalProgSal(&mp);
CalProgSal(&ap);
system("pause");
return;
}
虚函数和多态性使成员函数根据调用对象的类型产生不同的动作
面向抽象类编程(面向接口编程)是项目开发中重要技能之一
几个重要的面向对象思想:继承-组合、注入、控制反转(IOC)、MVC、aop
需求:
在系统框架中集成 Socket通信产品 和 加解密产品
Socket 通信产品:完成两点之间的通信;
加密产品:完成数据发送时加密;数据解密时解密;
设计:
CSocketProtocol
:Socket接口类
CSocketImp
:Socket产品类
CEncDesProtocol
:des接口类
CEncDesImp
:des产品类
int SckSendAndRec_EncDec()
class SocketAndEncDec
: 继承或组合
系统框架 ---> 接口层 <--- 产品
实现:
SocketProtocol.h
#pragma once
//接口层
//Socket接口类
class CSocketProtocol
{
public:
CSocketProtocol(){;}
// 虚析构函数
virtual ~CSocketProtocol(){;}
//---------------第一套api接口-----Begin---------------//
//客户端初始化 获取handle上下
virtual int cltSocketInit(/*out*/) = 0;
//客户端发报文
virtual int cltSocketSend(/*in*/ unsigned char* buf /*in*/, int buflen /*in*/) = 0;
//客户端收报文
virtual int cltSocketRev(/*in*/ unsigned char* buf /*in*/, int* buflen /*out*/) = 0;
//客户端释放资源
virtual int cltSocketDestory(/*in*/) = 0;
//---------------第一套api接口-----End---------------//
};
CEncDesProtocol.h
#pragma once
//接口层
//加解密接口类
class CEncDesProtocol
{
public:
CEncDesProtocol(){;}
~CEncDesProtocol(){;}
// 加密
virtual int EncData(unsigned char* plain, int plainlen, unsigned char* cryptdata, int* cryptlen) = 0;
// 解密
virtual int DecData(unsigned char* cryptdata, int cryptlen, unsigned char* plain, int* plainlen) = 0;
};
SocketImp.h
#pragma once
#include "SocketProtocol.h"
// socket产品类
// 继承接口,实现虚函数功能
class CSocketImp : public CSocketProtocol
{
public:
//客户端初始化 获取handle上下
int cltSocketInit(/*out*/);
//客户端发报文
int cltSocketSend(/*in*/ unsigned char* buf /*in*/, int buflen /*in*/);
//客户端收报文
int cltSocketRev(/*in*/ unsigned char* buf /*in*/, int* buflen /*out*/);
//客户端释放资源
int cltSocketDestory(/*in*/);
private:
unsigned char* buf; // 报文
int buflen; // 报文长度
};
SocketImp.cpp
#include "iostream"
using namespace std;
#include "SocketImp.h"
//客户端初始化 获取handle上下
int CSocketImp::cltSocketInit(/*out*/)
{
buf = NULL;
buflen = 0;
return 0;
}
//客户端发报文
int CSocketImp::cltSocketSend(/*in*/ unsigned char* buf /*in*/, int buflen /*in*/)
{
int ret = 0;
// 得到buf,分配内存
this->buf = new unsigned char[buflen];
if (this->buf == NULL)
{
ret = -1;
cout << "func cltSocketSend new err: " << ret << endl;
return ret;
}
memcpy(this->buf, buf, buflen);
this->buflen = buflen;
return ret;
}
//客户端收报文
int CSocketImp::cltSocketRev(/*in*/ unsigned char* buf /*in*/, int* buflen /*out*/)
{
int ret = 0;
if (buf == NULL || buflen == NULL)
{
ret = -1;
cout << "func cltSocketRev in NULL: " << ret << endl;
return ret;
}
memcpy(buf, this->buf, this->buflen);
*buflen = this->buflen;
return ret;
}
//客户端释放资源
int CSocketImp::cltSocketDestory(/*in*/)
{
if (buf != NULL)
{
delete buf;
buf = NULL;
buflen = 0;
}
return 0;
}
EncDesImp.h
#pragma once
#include "CEncDesProtocol.h"
// 加解密产品类
// 继承接口,实现虚函数功能
class CEncDesImp : public CEncDesProtocol
{
public:
// 加密
virtual int EncData(unsigned char* plain, int plainlen, unsigned char* cryptdata, int* cryptlen);
// 解密
virtual int DecData(unsigned char* cryptdata, int cryptlen, unsigned char* plain, int* plainlen);
};
EncDesImp.cpp
#include "iostream"
using namespace std;
#include "EncDesImp.h"
#include "des.h"
// 加密
int CEncDesImp::EncData(unsigned char* plain, int plainlen, unsigned char* cryptdata, int* cryptlen)
{
int ret = 0;
ret = DesEnc(plain, plainlen, cryptdata, cryptlen);
if (ret != 0)
{
ret = -1;
cout << "Func DesEnc() err: " << ret << endl;
return ret;
}
return ret;
}
// 解密
int CEncDesImp::DecData(unsigned char* cryptdata, int cryptlen, unsigned char* plain, int* plainlen)
{
int ret = 0;
ret = DesDec(cryptdata, cryptlen, plain, plainlen);
if (ret != 0)
{
ret = -1;
cout << "Func DesDec() err: " << ret << endl;
return ret;
}
return ret;
}
Test_Socket.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
#include "SocketImp.h"
#include "SocketProtocol.h"
#include "EncDesImp.h"
#include "CEncDesProtocol.h"
//面向抽象类编程,框架 C函数实现
int SckSendAndRec_EncDec(CSocketProtocol* sp, CEncDesProtocol* ed, unsigned char* in, int inlen, unsigned char* out, int* outlen)
{
int ret = 0;
// 临时数据
unsigned char data[4096];
int datalen = 0;
// 初始化 Socket
ret = sp->cltSocketInit();
if (ret != 0)
{
goto End;
}
// 加密输入的数据
ret = ed->EncData(in, inlen, data, &datalen);
if (ret != 0)
{
goto End;
}
// 发送加密的数据
ret = sp->cltSocketSend(data, datalen);
if (ret != 0)
{
goto End;
}
// 收到加密的数据
ret = sp->cltSocketRev(data, &datalen);
if (ret != 0)
{
goto End;
}
// 对加密的数据进行解密
ret = ed->DecData(data, datalen, out, outlen);
if (ret != 0)
{
goto End;
}
End:
ret = sp->cltSocketDestory();
return 0;
}
//面向抽象类编程,框架 C++类实现
//继承:抽象类在多继承中的应用
/*
class SocketAndEncDec : public CSocketProtocol, public CEncDesProtocol
{
};
*/
// 组合
class SocketAndEncDec
{
public:
SocketAndEncDec()
{
this->sp = NULL;
this->ed = NULL;
}
SocketAndEncDec(CSocketProtocol* sp, CEncDesProtocol* ed)
{
this->sp = sp;
this->ed = ed;
}
// 注入思想
void setSp(CSocketProtocol* sp)
{
this->sp = sp;
}
void setEd(CEncDesProtocol* ed)
{
this->ed = ed;
}
// 框架成员函数
int SckSendAndRec_EncDec_adv(unsigned char* in, int inlen, unsigned char* out, int* outlen)
{
int ret = 0;
// 临时数据
unsigned char data[4096];
int datalen = 0;
// 初始化 Socket
ret = this->sp->cltSocketInit();
if (ret != 0)
{
goto End;
}
// 加密输入的数据
ret = this->ed->EncData(in, inlen, data, &datalen);
if (ret != 0)
{
goto End;
}
// 发送加密的数据
ret = this->sp->cltSocketSend(data, datalen);
if (ret != 0)
{
goto End;
}
// 收到加密的数据
ret = this->sp->cltSocketRev(data, &datalen);
if (ret != 0)
{
goto End;
}
// 对加密的数据进行解密
ret = this->ed->DecData(data, datalen, out, outlen);
if (ret != 0)
{
goto End;
}
End:
ret = this->sp->cltSocketDestory();
return 0;
}
private:
CSocketProtocol* sp;
CEncDesProtocol* ed;
};
//test
void main()
{
int ret = 0;
// 准备测试案例
unsigned char in[4096];
int inlen;
unsigned char out[4096];
int outlen = 0;
strcpy((char*)in, "TestSocketAndEncDes");
inlen = 10;
// 框架 C函数实现
{
// 父类指针指向子类对象,实现多态
CSocketProtocol* sp1 = NULL;
CEncDesProtocol* ed1 = NULL;
sp1 = new CSocketImp;
ed1 = new CEncDesImp;
// 使用接口
ret = SckSendAndRec_EncDec(sp1, ed1, in, inlen, out, &outlen);
if (ret != 0)
{
cout << "Func SckSendAndRec_EncDec() err: " << ret << endl;
goto End;
}
// 释放
delete sp1; // 虚析构函数,通过父类指针释放所有的子类对象资源
delete ed1;
}
// 框架 C++类实现
{
SocketAndEncDec* mySAED = new SocketAndEncDec;
CSocketProtocol* sp2 = NULL;
CEncDesProtocol* ed2 = NULL;
sp2 = new CSocketImp;
ed2 = new CEncDesImp;
mySAED->setEd(ed2);
mySAED->setSp(sp2);
ret = mySAED->SckSendAndRec_EncDec_adv(in, inlen, out, &outlen);
if (ret != 0)
{
cout << "Func SckSendAndRec_EncDec_adv() err: " << ret << endl;
goto End;
}
delete sp2;
delete ed2;
delete mySAED;
}
End:
system("pause");
}
函数三要素:名称、参数、返回值
C语言中的函数有自己特定的类型
函数类型:typedef int Func(int, int);
函数指针:函数指针用于指向一个函数,函数名是函数体的入口地址;
(1)可以通过函数类型定义函数指针:Func* pFunc;
(2)可以直接定义:int (*Func)(int, int);
(1)数组指针(数组类型 --> 数组指针类型 --> 数组指针变量)
void main()
{
// 定义一个数组类型 int a[10];
{
typedef int (myTypeArr)[10];
myTypeArr myArr;
myArr[0] = 10;
printf("myArr[0]: %d\n", myArr[0]);
}
// 定义一个数组指针类型
{
int a[10] = { 0 };
// 定义类型
typedef int (*pTypeArr)[10];
// 使用类型定义变量
pTypeArr myPArr;
// 使用变量
myPArr = &a;
// 使用数组指针 指向 a数组
(*myPArr)[0] = 20;
printf("a[0]: %d\n", a[0]);
}
system("pause");
return;
}
(2)函数指针(函数类型 --> 函数指针类型 --> 函数指针变量)
int add(int a, int b)
{
printf("func add result: %d\n", a+b);
return a + b;
}
void main()
{
// 定义一个函数类型 int add(int a, int b)
{
// 定义类型
typedef int (myTypeFunc)(int, int);
// 使用类型定义指针变量
myTypeFunc* pFunc = NULL;
// pFunc = &add; &可以省略
pFunc = add;
pFunc(1, 2); //间接调用
}
// 定义一个函数指针类型
{
typedef int(*myPTypeFunc)(int, int);
// 直接使用函数指针类型 定义 函数指针变量
myPTypeFunc pFunc = NULL;
pFunc = add;
pFunc(3, 4);
}
// 函数指针
{
// 直接定义函数指针变量
int (*myPFunc)(int, int);
myPFunc = add;
myPFunc(5, 6);
}
system("pause");
return;
}
当函数指针操作函数的参数,传递给一个被调用函数,被调用函数就可以通过这个指针调用外部的函数,形成了回调
// 假设是不同实现者 实现的功能
int add(int a, int b)
{
printf("func add result: %d\n", a+b);
return a + b;
}
int sub(int a, int b)
{
printf("func sub result: %d\n", a - b);
return a - b;
}
int mul(int a, int b)
{
printf("func mul result: %d\n", a * b);
return a * b;
}
// 定义一个函数指针类型
typedef int (*myPTypeFunc)(int, int);
// 操作者,任务的编写, 函数指针做函数参数
// int Operator(int (*myPTypeFunc)(int, int))
int Operator(myPTypeFunc myFunc)
{
int n = myFunc(1, 2); // 间接调用
return n;
}
//任务的调用
void main()
{
// 使用回调函数
Operator(add);
Operator(sub);
Operator(mul);
system("pause");
return;
}
思路:
(1)任务的实现,任务的操作框架,任务的调用有效的分离;
(2)任务的框架不用改变,去调用不同的函数,实现不同的功能 --> 通过回调函数调用不同的函数;
(3)回调函数:提前定义了一个协议(把函数参数、函数返回值提前约定),实现解耦合;
显示调用dll中的函数:通过 LoadLibrary、GetProcAddress
TestDll
__declspec(dllexport) int myAdd(int a, int b);
__declspec(dllexport) int mySub(int a, int b);
__declspec(dllexport) int myMul(int a, int b);
__declspec(dllexport) int myDiv(int a, int b);
// 定义函数指针类型
typedef int(*myFunc)(int, int);
void main()
{
// 用函数指针类型 定义 函数指针变量
myFunc myAdd;
myFunc mySub;
myFunc myMul;
myFunc myDiv;
HINSTANCE hInstLibrary = LoadLibrary("c:/TestDLL.dll");
myAdd = (myFunc)GetProcAddress(hInstLibrary, "myAdd");
mySub = (myFunc)GetProcAddress(hInstLibrary, "mySub");
myMul = (myFunc)GetProcAddress(hInstLibrary, "myMul");
myDiv = (myFunc)GetProcAddress(hInstLibrary, "myDiv");
myAdd(1, 2);
mySub(2, 1);
myMul(1, 2);
myDiv(2, 1);
system("pause");
return;
}
动态库:抽象一个套接口,单独封装成模块,给别人调用,无法扩展;
框架:能自由扩展,自由的集成第三方的产品;
回调机制原理:
当具体事件发生时,调用者通过函数指针调用具体函数;
回调机制的将调用者和被调函数分开,两者互不依赖;
标签:this Once 指针变量 名称 利用 子类 方式 自己的 base
原文地址:https://www.cnblogs.com/2dx3906/p/13189739.html