第一个完整c/c++框架的构造学习——出自传智扫地僧c++教程

虚拟的数据传输接口

c实现(指针做函数参数的练习)

c_socket.h文件

//头文件写函数声明 .c文件写函数实现

//头文件注意点1  如果未定义,则定义,把函数声明包含进去
1#ifndef __C_SOCKET_H__
1#define __C_SOCKET_H__

//头文件注意点2
2#ifdef  __cplusplus//活动预处理  如果是c++编译器,引用语言的规范去编译
2extern "C" {
2#endif



//首先抽象出接口函数,实现 初始化 发送 接收 释放资源


int socketInit(void **handle/*void隐藏数据结构,**输出类型比输入高一*/);//构思需要哪些参数,在函数内构造出数据结构块,并传出内存块(指针+长度)
int socketSend(void *handle/*in*/,unsigned char *buf/*in*/,int buflen/*in*/ );
//参数  传入待传内存块(指针+长度)  此处的参数为什么都是输入类型的  
//传来的数据是用内存块的数据模拟的
int socketReceive(void *handle/*in*/,unsigned char *buf/*in*/,int *buflen/*out */);
//参数 待接收内存块(指针+长度)与 储存参数的内存块(指针+长度)
int socketDestroy(void *handle);//参数 所有分配的内存块(指针+长度)  释放


//第二套与第一套的区别
//------------------第二套接口---Begin--------------------------------//
//    int cltSocketInit2(void **handle); 

    //客户端发报文
//    int cltSocketSend2(void *handle, unsigned char *buf,  int buflen);
    //客户端收报文
//    int cltSocketRev2(void *handle, unsigned char **buf, int *buflen);    出现二级指针,则在函数内分配用来接收报文的内存空间
//    int cltSocketRev2_Free(unsigned char **buf);                          报文使用完之后把buf释放(free(*buf))且置成NULL(*buf = NULL)
    //客户端释放资源

//    int cltSocketDestory2(void **handle);                                  出现二级指针,把handle释放且置成NULL
//------------------第二套接口---End--------------------------------//

//头文件注意点3
3#ifdef  __cplusplus//
3}
3#endif

1#endif



c_socket.c文件

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "c_socket.h"

//要点 把数据抽象出一个结构体隐藏数据结构
typedef struct  socketHandle
{
	//没有考虑到的点
	char	version[64];  //传递的内存包的日志信息
	char	ip[128];  //传来的数据的ip地址
	int		port;//使用了串口几
	unsigned char *p;
	int		plen;
} SCK_HANDLE;

//写出具体函数实现

int socketInit(void **handle/*void隐藏数据结构,**输出类型比输入高一*/)
{
	int ret = 0 ;
	SCK_HANDLE *hdl = NULL;  //将数据块分配在堆上,而不是栈上(Init函数生命周期结束后会释放栈上的空间,导致数据块无法被其他函数使用)
	hdl = (SCK_HANDLE*)malloc(sizeof(SCK_HANDLE));
	if (hdl == NULL )
	{
		ret = -1;
		printf ("socketInit()err:%d",ret);
		return ret ;
	}
	memset(hdl,0,sizeof(SCK_HANDLE));
	//将分配好的内存空间首地址赋值给handle指针,*handle间接改变handle的指向
	*handle = hdl;//操作handle指向hdl分配好的数据块

	strcpy(hdl->version,"1.1.1");
	strcpy(hdl->ip,"192.168.1.1");
        //strcpy与memcpy的区别:strcpy仅用于字符串的复制,遇到\0自动停止,容易溢出,memcpy用于内存块的复制,多一个参数len,不易溢出
        hdl->port = 1;

	return ret;
}
//指针输入输出的判定:
//输出是函数内部分配内存返回函数指针  需要操作指针,故需要比所操作的指针高一级的指针
//输入是通过指针传递内存中的数据     需要操作内存数据,只需要内存块的地址就够了

 //构思需要哪些参数,在函数内构造出数据结构块,并传出内存块(指针+长度)
int socketSend(void *handle/*in*/,unsigned char *buf/*in*/,int buflen/*in*/ )
{
	int ret = 0;
	SCK_HANDLE *hdl = NULL;//用结构体把匿名的句柄接过来
	if(handle == NULL || buf == NULL || buflen == NULL)
	{
		ret = -1;
		printf ("socketSend()err:%d",ret);
		return ret ;
	}
	hdl = (SCK_HANDLE*)handle;
	hdl->p = (unsigned char *)malloc(buflen*sizeof(unsigned char));
	if (hdl->p == NULL )
	{
		ret = -2;
		printf ("socketSend()err:%d",ret);
		return ret ;
	}
	memset(hdl->p,0,buflen);
	memcpy(hdl->p,buf,buflen);
	hdl->plen = buflen;

	return ret;
}


//参数  传入待传内存块(指针+长度)  
//此处的参数为什么都是输入类型的 因为是把本地的数据发出去 
//发出的数据是将内存块的数据传入struct数据块中的
int socketReceive(void *handle/*in*/,unsigned char *buf/*in*/,int *buflen/*out */)
{
	int ret = -1;
	SCK_HANDLE *hdl = NULL;
	if(handle == NULL || buf == NULL || buflen == NULL)
	{
		ret = -1;
		printf ("socketReceive()err:%d",ret);
		return ret ;
	}
	hdl = (SCK_HANDLE*)handle;

	//模拟将数据块中的数据传到内存中去
	memcpy(buf,hdl->p,hdl->plen);
	*buflen = hdl->plen;
	
	return ret;
}


//参数 待接收内存块(指针+长度)与 储存参数的内存块(指针+长度)
int socketDestroy(void *handle)
{
	int ret = -1;
	SCK_HANDLE *hdl = NULL;
	if(handle == NULL)
	{
		ret = -1;
		printf ("socketdestroy()err:%d",ret);
		return ret ;
	}
	hdl = (SCK_HANDLE*)handle;
	//此处要记得先释放struct中的指针,再释放结构体空间,从底向上释放
	if(hdl->p != NULL)
	{
		free(hdl->p);
	}
	free(hdl);

	return ret;
}

//参数 所有分配的内存块(指针+长度)  释放

测试框架

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

//包含头文件,实际这里做的处理是宏替换,直接将c_socket.c文件全部替换到这里
#include "c_socket.h"
//< >引用的是编译器的类库路径里面的头文件
//" "引用的是你程序目录的相对路径中的头文件

int main ()
{
	//c的变量声明必须放在函数最前面  先定义后使用,否则编译出错
	int ret = 0;
	//void隐藏数据类型
	void* hdl = NULL;
	unsigned char inbuf[4096];
	int inbuflen = 0;
	unsigned char outbuf[4096] = "simulation data";
	int outbuflen = strlen((char*)outbuf);

	ret = socketInit(&hdl);
	
	//调用发送函数
	ret = socketSend(hdl ,outbuf ,outbuflen);

	//调用接收函数
	ret = socketReceive(hdl,inbuf,&inbuflen); 
	
	//调用析构函数
	ret = socketDestroy(hdl);
	
	printf("hello...\n");
	system("pause");

}

动态库的封装----------

1新建dll项目(工程1)

2在工程1 下建立.c文件, 将写好的函数实现粘贴进去,每个函数前加关键字 _declpec(dllexport),编译后即可在debug目录中生成.lib(资源模式文件) .dll(动态库)

3测试框架(工程2)动态库使用时需配合函数声明.h  .lib(资源模式文件)  .dll(动态库) 一起放置于调用dll的项目.cpp平行目录下,并在项目属性中->配置属性->链接器->输入->附加依赖项中 粘贴入.lib文件的文件名.lib;

4重新生成项目即可调用dll;

也可以在函数编写阶段实现动态库的调试编写,将工程1下打好桩的函数实现导出动态库调用到工程2下,在测试框架中调用函数,调试时完善函数。



c++(抽象类的继承  实现测试框架与接口分离)

定义抽象类,虚函数作为接口   抽象类.h

//避免函数头文件重复包含
#pragma once

//写出抽象类

class CSocketAbstract
{
public:
	//类的构造函数,析构函数
	CSocketAbstract()
	{
		;
	}
	~CSocketAbstract()
	{
		;
	}
/*  先写出接口
	int CSocketInit();
	int CSocketSend(unsigned char *buf /in/,int buflen  /in/);
	int CSocketReceive(unsigned char *buf /in/,int *buflen/out/);
	int CSocketDestroy();
*/
//写成纯虚函数的形式(含有纯虚函数的类叫做抽象类)
	virtual int CSocketInit() = 0;
	virtual int CSocketSend(unsigned char *buf /*in*/,int buflen  /*in*/) = 0;
	virtual int CSocketReceive(unsigned char *buf /*in*/,int *buflen/*out*/) = 0;
	virtual int CSocketDestroy() = 0;
	//下一步,
	
};//类声明这个分号别忘

抽象类作为对厂商程序的规范

厂商继承抽象类,将纯虚函数实例化,并加入需要的属性和方法 厂商类.h

//厂商1的继承抽象函数,并声明函数
#include <iostream>
using namespace std;
#include "c++_socket.h"
//继承的语法
class CSocket1 : public CSocketAbstract
{
public:
	virtual int CSocketInit();
	virtual int CSocketSend(unsigned char *buf /*in*/,int buflen  /*in*/);
	virtual int CSocketReceive(unsigned char *buf /*in*/,int *buflen/*out*/);
	virtual int CSocketDestroy();
private:
	unsigned char * p;
	int	plen;
};//类声明这个分号别忘

厂商类的具体实现.cpp

#include <iostream>
using namespace std;
#include "c++_socket1.h"
//开始打桩   先打桩,写好测试框架再写函数的具体实现

int CSocket1::CSocketInit()
{
	int ret = 0 ;
	this->p = NULL;
	this->plen = 0;
	return ret ;
}
 
int CSocket1::CSocketSend(unsigned char *buf /*in*/,int buflen  /*in*/)
{
	int ret = 0 ;
	if(buf == NULL)
	{
		ret = -1;
		cout<<"CSocketSend()err:%d"<<ret<<endl;
		return ret;
	}
	this->p = new unsigned char [buflen];
	if(this->p == NULL)
	{
		ret = -2;
		cout<<"CSocketSend()err:%d"<<ret<<endl;
		return ret;
	}

	memcpy(this->p,buf,buflen);
	this->plen = buflen ;

	return ret ;
}
 
int CSocket1::CSocketReceive(unsigned char *buf /*in*/,int *buflen/*out*/)
{
	int ret = 0 ;

	memcpy(buf,p,plen);
	*buflen = plen;

	return ret ;
}
 
int CSocket1::CSocketDestroy()
{
	int ret = 0 ;

	if(p != NULL)
	{
		delete [] p ;
		p = NULL;
		plen = 0;
	}

	return ret ;
}
 

测试框架.cpp,发生多态的三个条件:1继承,2虚函数重写父类函数,3父类指针传入子类对象

#include <iostream>
using namespace std;

#include "c++_socket1.h"

int Test(CSocketAbstract * test)
{
	int ret = 0;
	unsigned char outbuf[4096] = "simulation data ";

	int outbuflen = strlen((char*)outbuf); 
	unsigned char inbuf[4096];
	int inbuflen = 0; 
	ret = test->CSocketInit();

	ret = test->CSocketSend( outbuf,outbuflen);

	ret = test->CSocketReceive(inbuf,&inbuflen);

	ret = test->CSocketDestroy();

	return ret;
}
int main ()
{
	int ret = 0;
	
	CSocketAbstract * sp = NULL;
	CSocket1 hdl ;
	//*sp = hdl;//错误使用 抽象类不能实例化
	sp = &hdl;//抽象类指针 = 子类对象的地址
	//发生多态的三个条件
	//1继承
	//2虚函数重写父类的函数
	//3父类指针传入子类对象,传入父类调父类,传入子类调子类
	//不能声明抽象类对象,可以声明抽象类指针,,可以声明抽象类引用
	ret = Test( sp);
	
	cout<<"hello..."<<endl;
	system("pause");
	return ret;


}

以上两个框架是通过c/c++分别完成了框架编程

抽象类的使用完成了厂家程序和框架的解耦合,两方都有统一的规范——接口

如何在c函数中实现解耦合呢

提出了函数指针做函数参数 回调函数的思想

将所使用的厂商程序函数入口地址作为参数传入框架或者封装入动态库,在使用动态库时,通过传入的参数自动调用动态库外的函数

函数指针的语法推演

定义int add (int a ,int b)

{

return a+b;
}

1函数类型

typedef int (Mytypefunc)(int a,int b)

Mytypefunc* myfunc = NULL;

myfunc = & add;

2函数指针类型   约定接口类型参数

typedef int (*Mytypefunc)(int a ;int b);

Mytypefunc myfunc ;

myfunc = add;

myfunc(5,5);//调用函数

3函数指针变量  实例化函数指针传入函数

int (*Mytypefunc)(int a, int b);

Mytypefunc = add;

Mytypefunc(5,5);

利用函数指针类型再框架中预留第三方函数的位置

1 .h 头文件中声明函数指针类型 并更改函数声明

//用户使用函数DesEnc加密
typedef int (*DesEncFuncType)(unsigned char *pInData,int nInDataLen,unsigned char *pOutData,int *pOutDataLen);
//用户使用函数DesDec解密
typedef int (*DesDecFuncType)(unsigned char *pInData,int nInDataLen,unsigned char *pOutData,int *pOutDataLen);
int socketSend(void *handle/*in*/,DesEncFuncType DesEncFunc ,unsigned char *buf/*in*/,int buflen/*in*/ );
int socketReceive(void *handle/*in*/,DesDecFuncType DesDecFunc ,unsigned char *buf/*in*/,int *buflen/*out */);

2 .c 文件中更改函数实现

int socketSend(void *handle/*in*/,DesEncFuncType DesEncFunc ,unsigned char *buf/*in*/,int buflen/*in*/ )
{
	int ret = 0;
	SCK_HANDLE *hdl = NULL;//用结构体把匿名的句柄接过来
	unsigned char tmpbuf[4096];
	int tmpbuflen = 0;
	if(handle == NULL || buf == NULL || buflen == NULL)
	{
		ret = -1;
		printf ("socketSend()err:%d",ret);
		return ret ;
	}
	hdl = (SCK_HANDLE*)handle;
	
	//用户使用的函数
	//int DesEnc(
		//unsigned char *pInData,
		//int            nInDataLen,
		//unsigned char *pOutData,
		//int           *pOutDataLen);
	//集成加密函数  将加密后的文件发送至模拟云端结构体SCK_HANDLE
	memset(tmpbuf,0,sizeof(tmpbuf));
	tmpbuflen = strlen((char *)tmpbuf);
	ret = DesEncFunc(buf,buflen,tmpbuf,&tmpbuflen);
	if (ret != 0 )
	{
		printf ("DesFunc()err:%d",ret);
	}

	hdl->p = (unsigned char *)malloc(tmpbuflen*sizeof(unsigned char));
	if (hdl->p == NULL )
	{
		ret = -2;
		printf ("socketSend()err:%d",ret);
		return ret ;
	}

	memset(hdl->p,0,tmpbuflen);
	memcpy(hdl->p,tmpbuf,tmpbuflen);//拷贝时越界所以造成free(hdl->p)出错
	hdl->plen = tmpbuflen;

	return ret;
}
int socketReceive(void *handle/*in*/,DesDecFuncType DesDecFunc, unsigned char *buf/*in*/,int *buflen/*in,out */)
{
    int ret = -1;
    unsigned char tmpbuf[4096];
    int tmpbuflen = 0;
    SCK_HANDLE *hdl = NULL;
    if(handle == NULL || buf == NULL || buflen == NULL)
    {
        ret = -1;
        printf ("socketReceive()err:%d",ret);
        return ret ;
    }
    hdl = (SCK_HANDLE*)handle;
    memset(tmpbuf,0,tmpbuflen);
    ret = DesDecFunc(hdl->p,hdl->plen,tmpbuf,&tmpbuflen);
    //模拟将数据块中的数据经解密后传到内存中去
    memcpy(buf,tmpbuf,tmpbuflen);
    *buflen = tmpbuflen;
    
    return ret;
}



3 在.c测试框架中更改函数调用,添加第三方加解密头文件和函数实现文件到项目目录

#include "des.h"//添加第三方加解密头文件

//调用发送函数
	ret = socketSend(hdl ,DesEnc ,outbuf ,outbuflen);

	//调用接收函数
	ret = socketReceive(hdl,DesDec ,inbuf,&inbuflen);

free() 时堆出错

1 释放一个空指针

2 重复释放

3 释放一个非自己申请的内存,或者释放的指针指向的地方不是本进程申请的。

4 申请的内存块写过界了或者被写过界了,此时内存块就被破坏了,释放的时候为了避免释放掉其他有用的数据,是会报错。

情况4是本程序编写过程中出现的问题,在集成了加解密算法之后,加密后的字符长度发生了变化,而程序仍按照输入字符的长度来分配内存,虽然使用memcpy len限制来避免过界,仍造成了cpy的字符长度超出了分配内存的限制,导致free(hdl->p)时出现了堆错误










  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录 01_初学者的企业用人标准寻找引言 02_socketclient_api模型的抽象_初学者应知的标准_传扫地 03_本套视频总体课程简介 04_就业班课程总体简介_课堂答疑 05_初学者建立信心 06_学员学习标准_排序及问题抛 07_数组做函数参数退化问题剖析_传扫地 08_数据类型基础提高 09_数据类型引申和思考 10_变量本质剖析和内存四区模型引_传扫地 11_c的学习重理解到位_对初学者_传扫地 12_直接通过内存标号操作内存空间_课堂答疑 13_中午课程回顾 14_内存四区基本原理_全局区案例理解 15_内存四区_堆栈案例理解 16_课堂答疑_理解指针的关键关键在内存 17_vs20102013上配置#系列快捷方式 18_栈的属性和buf地址增长方向是两个不同的概念 19_函数调用模型_主调函数和被调用函数 20_课堂答疑_函数调用流程入栈栈过程 21_指针也是一种数据类型_基础 22_指针也是一种数据类型_强化_传扫地 源码及文档 01_课程回顾 02_作业题强化和野指针 03_向null地址copy数据和不断改变指针指向强化 04_有关字面量 05_间接赋值从0级指针到1级指针 06_间接赋值从1级指针到2级指针_技术推演_传扫地 07_间接赋值是指针存在的最大意义 08_间接赋值成立的三个条件和应用场景 09_指针学习思路应用清晰起来 10_指针强化3和指针强化4思想讲解 11_字符串的基本操作 12_数组中括号与指针关系和数组名常量指针分析 13_字符串一级指针内存模型_传扫地 14_字符串copy函数技术推演 15_字符串copy函数强化训练_判断null_引入辅助指针变量_传扫地 16_项目开发模型强化_strstr_while模型_重要 17_作业考试强化 源码及文档 01_上一次课程回顾 02_两头堵模型 03_字符串反转_方法1指针 04_字符串反转_方法2递归逆序(3个点)_传扫地 05_考试题解答和项目开发代码书写手法 06_一级指针易错模型分析_重点 07_C语言中的const知识点总结 08_指针的输入和输模型 09_课堂答疑_指针所指向内存释放 10_二级指针做输入_第1种内存模型 11_二级指针做输入_第2种内存模型 12_二级指针做输入_第2种内存模型_课堂答疑_多维数组名本质抛砖 13_二级指针做输入_第3种内存模型_传扫地 14_二级指针三种内存模型示意图_传扫地 15_玩转多级指针_传扫地 16_两个辅助指针变量挖字符串测试框架搭建 18_作业 源码及文档 01_课程回顾 02_两个赋值指针变量挖字符训练_第3种内存模型_传扫地 03_多级指针的野指针问题(释放问题)_传扫地 04_学员作业点评_典型错误吸取教训 05_数组类型 06_数组指针类型和定义数组指针变量的3种方法 07_多维数组名本质剖析_传扫地 08_多维数组的【】和多级指针星号转化推演 09_多维数组做函数参数技术推演和退化原因抛 10_多维数组做函数参数退化总结_ 11_指针数组的应用场景01 12_指针数组自我结束能力(三种表示方法) 13_干活要知道在什么框架之下干活 14_结构体类型和变量定义及基本操作 15_结构体元素做函数参数pk结构指针做函数参数 16_结构体做函数基本操作 17_结构体做函数内存分配指针 18_结构中套一级指针 19_结构体中套二级指针_传扫地 20_作业强化 21_C提高课程_day01-day04_知识体系梳理_传扫地 源码及文档 01_上次课程回顾 02_二级指针三种内存模型综合训练_框架搭建 03_二级指针三种内存模型综合训练_实现 04_二级指针三种内存模型综合训练_典型错误 05_结构体作业点评 06_结构体中的深copy和浅copy 07_结构中的高级话题_偏移量 08_结构中的高级话题_偏移量强化 09_文件操作api基本概念 10_按照字符读写文件 11_按照行方式操作文件 12_按照块的方式操作文件 13_中午课程回顾 14_配置文件读写案例功能介绍 15_配置文件读写案例_接口设计 16_配置文件读写案例_集成框架搭建 17_配置文件读写案例_读配置项实现 18_配置文件读写案例_写和修改接口实现 19_文件加密案例_思路分析 20_文件加密案例_文件搬运实现 21_文件加密案例_文件加密功能集成 22_文件加密案例_文件加密实现 23_作业 24_学员二级指针代码bug调试_传扫地 源码及文档 01_课程回顾 02_解密作业 03_指针用法杂项 04_再谈多级指针做输_传扫地 05_动态库的基本概念和使用 06_动态库测试环境和调试环境搭建 07_socketclient动态库函数_初始化实现wmv 08_socketclient动态库函数_发送接受释放实现wmv 09_socketclient动态库_第二套api函数_传扫地 10_socketclient动态库_日志功能集成 11_项目中检索内存泄漏使用和基本原理 12_动态库基本知识和环境调试注意 13_动态库内存释放问题 源码及文档 01_上一次课程回顾 02_链表热身_结构体中套元素和指针 03_结构体数据类型的嵌套定义和函数的嵌套调用是两个不同的概念 04_静态链表及局限性 05_链表的分类和链表的辅助指针变量 06_链表api函数搭建 07_链表的创建和打印 08_链表的插入操作和辅助指针变量分析_传扫地 09_链表的删除和销毁 10_链表的逆置_传扫地 11_链表的逆置_课堂答疑 12_课堂答疑pheadnextnext 13_中午课程回顾 14_传统链表和非传统链表 15_链表的技术体系推演 16_通用链表库集成和测试 17_C提高课程_day05-day07_知识体系梳理_传扫地 源码及文档 第二部分 C++基础目录 01_C++基础课程的安排和需要持之以恒的学习态度 02_简单的C++程序helloworld 03_用面向过程和面向对象方法求解圆形面积_类和对象的关系思考_传扫地 04_类中不写成员函数易犯错误模型 05-易犯错误模型-为什么需要成员函数(补充资料)-传扫地 06_课堂答疑类中写成员函数_调用的时才会执行 07_程序设计方法发展历程 08_C语言和C++语言的关系_工作经验分享 09_namespace和iotream 10_实用性加强_register增强_检测增强 11_struct关键字类型增强 12_c++类型类型检查加强 13_新增数据类型bool类型 14_中午课程回顾 15_c++中的三目运算符_传扫地 16_const的基础和const符号表机制探究_传扫地 17_const和#define的对比_传扫地 18_引用的基础知识(定义和函数参数) 19_复杂数据类型引用做函数参数__传扫地 20_引用的本质剖析_传扫地 21_函数返回值是引用(当左值右值)_传扫地 源码及文档 01_上一次课程复习 02_指针的引用_传扫地 03_常引用 04_inline内联函数 05_函数参数相关扩展 06_函数重载 07_函数重载和函数指针在一起 08_中午课程回顾 09_c++学习路线和c++基础课程学习标准_传扫地 10_类的封装和访问控制 11_struct和class关键字区别 12_类的声明和类的实现分开 13_面向过程向面向对象转变案例1 14_面向过程向面向对象转变案例2 15_面向过程向面向对象转变案例3 16_作业 17_C++基础课程day01-day02_知识体系梳理_传扫地 源码及文档 01_上一次课程回顾 02_构造和析构的基础知识 03_构造和析构的用途演示 04_构造函数的调用(无参数和有参构造)_传扫地 05_课堂答疑对象的初始化和对象的赋值是两个不同的概念 06_为什么需要构造和析构函数 07_copy构造函数的调用时机1和2 08_课堂答疑 09_copy构造函数调用时机3_传扫地 10_copy构造函数调用时机4_函数返回值是匿名对象_传扫地 11_copy构造函数调用时机4_函数返回值是匿名对象的去和留的剖析_传扫地 12_构造和析构的重点整理 13_构造和析构总结 14_中午课程复习 15_构造函数的调用规则研究 16_浅拷贝问题抛 17_浅拷贝问题分析_传扫地 18_浅拷贝问题解决_深拷贝_显示编写拷贝构造函数 19_深拷贝和浅拷贝_默认的等号操作符也是浅拷贝_传扫地 20_构造函数的初始化列表 21_强化训练1_构造和析构调用顺序 22_强化训练2_匿名对象生命周期 23_强化训练3_构造中调用构造(产生匿名对象)_传扫地 24_new和delete的基本语法 25_new和delete的深入分析 26_静态成员变量和静态成员函数 27_C++面向对象模型初探_传扫地 28_this指针 29_作业 源码及文档 01_上一次课程回顾 02_const修饰的是谁_传扫地 03_this的const修饰课堂答疑 04_全局函数pk成员函数(返回元素,引用,星号this) 05_强化训练数组类_类的设计和测试程序 06_强化训练数组类_类的实现和测试 07_友元函数 08_友元类 09_运算符重载入门基础推演_传扫地 10_运算符重载语法理论知识介绍 11_中午课程回顾 12_成员函数和友元函数完成二元运算符重载 13_成员函数和友元函数完成一元运算符重载(前置) 14_成员函数和友元函数完成一元运算符重载(后置) 15_友元函数实现左移右移操作符重载(函数返回值当左值需返回引用)_传扫地 16_友元函数实现操作符重载知识总结 17_重载等号操作符_传扫地 18_数组类小案例_操作符重载需求 19_数组类小案例_重载[]_传扫地 20_数组类小案例_重载等号_传扫地 21_数组类小案例_重载==和!= 22_作业 源码及文档 01_上一次课程的回顾 02_()运算符重载 03_逻辑与和逻辑或运算符重载说明 04_课堂答疑_逻辑与和逻辑或运算符重载 05_MyString类案例_构造和析构函数 06_MyString类案例_重载等号和数组操作符_传扫地 07_MyString类案例_重载左移操作符 08_MyString类案例_重载双等号和不等号 操作符 09_MyString类案例_重载大于和小于操作符 10_MyString类案例_其他技巧 11_MyString类案例_重载右移操作符 12_C++基础课程day03-day05_知识体系梳理 13_作业和考试 源码及文档 01_继承的概念 02_子类可以访问父类的属性和方法 03_派生类的访问控制 04_派生类的访问控制综合训练_传扫地 05_类型兼容性原则_传扫地 06_继承中的构造和析构 07_继承和组合混搭下的构造和析构_传扫地 08_继承中的同名成员变量和同名成员函数 09_继承的static关键字 10_多继承的基本语法 11_二义性和虚继承解决方案 12_中午课程回顾 13_多继承原理抛砖_传扫地 14_多态思想引言 15_类型兼容性原则遇上还是函数重写_面向对象新需求_传扫地 16_多态案例_多态的意义_多态成立的三个条件_传扫地 17_多态案例丰富多彩和多态的理论知识 18_虚析构函数 19_重载重写重定义_问题抛 20_重载重写重定义_概念分析_传扫地 21_重载重写重定义_课堂答疑_传扫地 文档和源码 01_上一次课程回顾 02_多态原理探究_传扫地 03_证明vptr指针的存在 04_子类的vptr指针是分步初始化的_传扫地 05_面试题强化_多态相关 06_父类指针的步长和子类指针的步长不一样 07_课堂答疑什么时候子类的步长和父类的步长一样 08_抽象类基本语法 09_抽象类在多继承中的应用 10_面向抽象类编程_计算程序员工资 11_中午课程回顾 12_信息系统框架集成第三方产品案例_背景和需求 13_信息系统框架集成第三方产品案例_编码实现分析_传扫地 14_信息系统框架集成第三方产品案例_socket抽象类和框架搭建__传扫地 15_信息系统框架集成第三方产品案例_框架实现第一个socket类厂商实现 16_信息系统框架集成第三方产品案例_第二个socket类厂商实现 17_信息系统框架集成第三方产品案例_加解密抽象类和加解密厂商类实现 18_信息系统框架集成第三方产品案例_集成测试加密厂商和socket厂商入围 19_信息系统框架集成第三方产品案例_集成框架变成类方式_传扫地 20_信息系统框架集成第三方产品案例_几个重要的面向对象思想_传扫地 21_作业 文档和源码 01_上一次课程回顾 02_数组指针语法梳理 03_函数指针语法梳理_传扫地 04_函数指针做函数参数思想剖析_传扫地 05_函数指针的正向调用案例 06_C动态库升级成框架案例_项目需求和基本思想_传扫地 07_C动态库升级成框架案例_开发环境搭建 08_C动态库升级成框架案例_方法1动态库中直接添加回调函数_传扫地 09_C动态库升级成框架案例_方法2把回调函数缓存到动态库_编写 10_C动态库升级成框架案例_方法2把回调函数混存到动态库_测试 11_C++基础课程day06-day08_知识体系梳理 文档和源码 第三部分 C++进阶部分目录 01_上一次课程知识点_梳理 02_函数模板为什么和函数模板语法基础 03_课堂答疑_遇到莫名其妙的问题_重新编译 04_函数模板当函数参数 05_普通函数和模板函数区别_传扫地 06_函数模板和函数重载在一起(调用规则研究)_传扫地 07_函数模板机制探究上 08_函数模板机制探究下_传扫地 09_课堂答疑_二次编译 10_类模板语法_数据类型和算法的分离_抛砖 11_单个类模板基本语法 12_类模板_派生_普通类语法 13_类模板_派生_类模板语法 14_中午知识点梳理 15_复数类_所有函数都写在类的内部 16_复数类_所有函数都写在类的外部_上 17_复数类_所有函数都写在类的外部_下 18_复数类_所有函数都写在类的外部(h和cpp分开) 19_类模板中的static关键字 20_案例_数组模板类_需求和类的初步设计 21_案例_数组模板类_测试框架搭建 22_案例_数组模板类_类的实现和测试_传扫地 23_案例_数组模板类_数组元素存储的是类对象思想抛砖_传扫地 24_作业 代码 文档 01_泛型编程_知识点梳理 02_模板数组类_作业讲解和思想强化(数据类型和算法的分离)_传扫地 03_类型转换_static_cast和reinterpret_cast 04_类型转换_dynamic_cast和reinterpret_cast_传扫地 05_类型转换_const_cast 06_异常的基本语法 07_异常机制基本思想梳理 08_栈解旋unwinding 09_异常接口声明 10_异常类型_异常变量的生命周期上 11_异常类型_异常变量的生命周期下_传扫地 12_中午知识点梳理 13_异常的层次结构_传扫地 14_标准异常库 15_流类库结构 16_标准IO_输入api_上 17_标准IO_输入api_下 18_标准IO输_api和格式控制 19_文件的读写 代码 文档 01_stl总体课程安排 02_stl容器算法迭代器三大概念入门 03_stl理论知识_基本概念串讲 04_stl的string的典型操作1_初始化_遍历_连接_和字符指针转化_查找替换传扫地 05_stl的string的典型操作2_删除和插入 06_stl的string的常用算法 07_vector基本操作_对象创建_头部尾部操作元素_数组方式遍历vector 08_vector的迭代器遍历和迭代器的种类_传扫地 09_vector基本操作_删除和插入_传扫地 10_中午知识点回顾 11_deque容器基本操作 12_stack栈模型 13_queue模型 14_list容器模型基本操作 15_优先级队列priority_queue基本操作 16_set容器_插入_遍历_基本数据类型比较 17_set容器_自定义数据类型排序(仿函数应用)_insert判断返回值(pair的使用)_传扫地_ 18_set容器_find查找_equal_range(pair的使用)_传扫地_ 19_multiset容器基本操作_ 文档 源码 01_上一次课程知识点回顾 02_map容器基本操作_插入和插入结果判断_传扫地 03_map容器基本操作_查找和查找的异常处理 04_multimap容器案例_按照部门_增删改查员工信息 05_容器的值拷贝语意 06_各个容器特点比较 07_stl算法设计理念_函数对象和函数对象当参数和返回值_传扫地 08_stl算法设计理念_一元函数对象和一元谓词 09_中午课程知识点回顾 10_stl算法设计理念_二元函数对象和二元谓词 11_stl算法设计理念_二元谓词在set集合的应用 12_stl算法设计理念_预定义函数对象和函数适配器1_传扫地 13_stl算法设计理念_预定义函数对象和函数适配器2_案例_传扫地 14_stl容器算法迭代器的设计理念_重要理论思想总结_传扫地 15_stl的算法概念和分类 16_stl算法_foreach和transform基本使用 17_stl算法_foreach和transform算法比较_transform算法源码追踪_传扫地 文档 源码 01_上一次课程复习 02_stl常用算法_查找相关 03_stl常用算法_排序相关 04_stl常用算法_拷贝和替换相关 05_stl常用算法_算法和生成 06_stl常用算法_集合运算 07_STL案例_演讲比赛_比赛介绍和需求分析 08_STL案例_演讲比赛_搭建案例框架_传扫地 09_STL案例_演讲比赛_实现思路分析_传扫地 10_STL案例_演讲比赛_业务函数实现_产生选手和选手抽签 11_STL案例_演讲比赛_业务函数实现_选手比赛_传扫地 12_STL案例_演讲比赛_业务函数实现_比赛晋级结果打印 13_STL课程_知识体系梳理_传扫地 文档 源码 第四部分 01_数据结构课程_学习思路_学习基础 02_数据结构概念_基本概念 03_数据结构概念_逻辑关系_物理结构 04_算法基本概念和大O表示 05_算法的时间复杂度 06_算法的空间复杂度_空间换时间案例 07_课堂答疑_学员思路 08_线性表的理论知识梳理_重点在链表算法和具体数据类型的分离 09_线性表顺序存储设计和实现_环境搭建 10_线性表顺序存储设计和实现_api函数实现1 11_线性表顺序存储设计和实现_api函数实现2_插入算法 12_线性表顺序存储设计和实现_api函数实现3_get和delete 13_线性表顺序存储设计和实现_总结 14_线性表链式存储_设计与实现_框架搭建和链表技术领域推演_传扫地 15_线性表链式存储_设计与实现_api实现_传扫地 16_线性表链式存储_设计与实现_api实现下_传扫地 17_线性表链式存储_总结 18_c++模板链表_类设计和测试框架搭建 19_c++模板链表_类实现 代码 文档 01_数据结构day01_知识点梳理 02_c++链表模板类_思想加强 03_循环链表api熟悉 04_循环链表应用_约瑟夫问题求解 05_循环链表_插入算法分析_传扫地 06_循环链表_删除算法分析 07_循环链表_游标课堂答疑 08_循环链表_api串讲 09_循环链表_api熟悉 10_栈的顺序存储_设计与实现_测试框架搭建 11_中午课程回顾 12_栈模型和链表模型_顺序存储_思想分析_传扫地 13_栈的顺序存储_设计与实现_api实现和调试 14_栈的顺序存储_设计与实现_课堂答疑 15_栈链式存储_设计与实现_测试框架搭建 16_栈链式存储_设计与实现_栈结点转换成链表结点_思想分析_传扫地 17_栈链式存储_设计与实现_api实现_传扫地 18_栈链式存储_设计与实现_内存管理 19_栈的应用案例_就近匹配 20_栈的应用案例_中缀转后缀 21_栈的应用案例_基于后缀表达式的计算_传扫地 22_栈的应用案例_程序讲解 23_树模型抛砖 代码 文档 01_上一次课程_知识点回顾 02_队列顺序存储_设计与实现_测试框架 03_队列顺序存储_设计与实现_api函数的实现 04_队列链式存储_设计与实现_测试框架 05_队列链式存储_设计与实现_api函数实现 06_树的概念_定义_表示法_二叉树转换_树的存储 07_二叉树的概念_定义和性质 08_二叉树的概念_表示法_二叉树遍历 09_中午课程回顾 10_二叉树编程_遍历本质剖析和递归方式遍历_传扫地 11_二叉树编程案例1_求叶子结点的数目 12_二叉树编程案例2和3_求树高度_拷贝二叉树 13_二叉树编程案例_课堂答疑 14_树非递归中序遍历_思想分析 15_树非递归中序遍历_遍历过程演示 16_树非递归中序遍历_实现(stl方式)_传扫地 17_stl栈模型组合容器类对象_思想抛砖 18_创建树思想抛砖 代码 文档 01_上一次课程回顾 02_创建树_先序和中序确定树 03_学习数据结构_常用工具介绍 04_创建树_#号法 05_创建树_#号法编程实践 06_创建树_#号法课堂答疑 07_线索化_概念_过程分析 08_线索化_两个赋值指针变量线索化思想 09_线索化_线索化初始化流程 10_线索化_遍历思想 11_线索化_遍历树时,把结点插入链表中 12_中午课程总结和线索化逆序访问 13_霍夫曼树概念 14_排序_概念 15_排序_选择法 16_排序_插入法 17_排序_冒泡 18_排序_希尔排序 19_排序_希尔排序_分组很重要 20_排序_快速排序 21_排序_归并 22_数据结构课程_知识体系梳理 代码 文档 01_上一次课程知识点回顾 02_递归需要需要掌握的点补充 03_链表类_链式存储_测试 04_链表类_链式存储_api实现 05_链表类_链式存储_课堂答疑 06_栈类_链式存储_api实现 07_队列类_链式存储设计与实现_api 08_链表类_顺序存储_类设计和测试框架 09_链表类_顺序存储_类api实现 10_栈类_顺序存储_实现 11_队列类_顺序存储设计与实现 c++基础串讲复习1 c++基础串讲复习2 c++基础串讲复习3 c++基础串讲复习4 c++基础串讲复习5 代码 数据结构书籍和工具收集 文档 第四部分 C和C++与数据结构基础 01_数据结构课程_学习思路_学习基础 02_数据结构概念_基本概念 03_数据结构概念_逻辑关系_物理结构 04_算法基本概念和大O表示 05_算法的时间复杂度 06_算法的空间复杂度_空间换时间案例 07_课堂答疑_学员思路 08_线性表的理论知识梳理_重点在链表算法和具体数据类型的分离 09_线性表顺序存储设计和实现_环境搭建 10_线性表顺序存储设计和实现_api函数实现1 11_线性表顺序存储设计和实现_api函数实现2_插入算法 12_线性表顺序存储设计和实现_api函数实现3_get和delete 13_线性表顺序存储设计和实现_总结 14_线性表链式存储_设计与实现_框架搭建和链表技术领域推演_传扫地 15_线性表链式存储_设计与实现_api实现_传扫地 16_线性表链式存储_设计与实现_api实现下_传扫地 17_线性表链式存储_总结 18_c++模板链表_类设计和测试框架搭建 19_c++模板链表_类实现 代码 文档 01_数据结构day01_知识点梳理 02_c++链表模板类_思想加强 03_循环链表api熟悉 04_循环链表应用_约瑟夫问题求解 05_循环链表_插入算法分析_传扫地 06_循环链表_删除算法分析 07_循环链表_游标课堂答疑 08_循环链表_api串讲 09_循环链表_api熟悉 10_栈的顺序存储_设计与实现_测试框架搭建 11_中午课程回顾 12_栈模型和链表模型_顺序存储_思想分析_传扫地 13_栈的顺序存储_设计与实现_api实现和调试 14_栈的顺序存储_设计与实现_课堂答疑 15_栈链式存储_设计与实现_测试框架搭建 16_栈链式存储_设计与实现_栈结点转换成链表结点_思想分析_传扫地 17_栈链式存储_设计与实现_api实现_传扫地 18_栈链式存储_设计与实现_内存管理 19_栈的应用案例_就近匹配 20_栈的应用案例_中缀转后缀 21_栈的应用案例_基于后缀表达式的计算_传扫地 22_栈的应用案例_程序讲解 23_树模型抛砖 代码 文档 01_上一次课程_知识点回顾 02_队列顺序存储_设计与实现_测试框架 03_队列顺序存储_设计与实现_api函数的实现 04_队列链式存储_设计与实现_测试框架 05_队列链式存储_设计与实现_api函数实现 06_树的概念_定义_表示法_二叉树转换_树的存储 07_二叉树的概念_定义和性质 08_二叉树的概念_表示法_二叉树遍历 09_中午课程回顾 10_二叉树编程_遍历本质剖析和递归方式遍历_传扫地 11_二叉树编程案例1_求叶子结点的数目 12_二叉树编程案例2和3_求树高度_拷贝二叉树 13_二叉树编程案例_课堂答疑 14_树非递归中序遍历_思想分析 15_树非递归中序遍历_遍历过程演示 16_树非递归中序遍历_实现(stl方式)_传扫地 17_stl栈模型组合容器类对象_思想抛砖 18_创建树思想抛砖 代码 文档 01_上一次课程回顾 02_创建树_先序和中序确定树 03_学习数据结构_常用工具介绍 04_创建树_#号法 05_创建树_#号法编程实践 06_创建树_#号法课堂答疑 07_线索化_概念_过程分析 08_线索化_两个赋值指针变量线索化思想 09_线索化_线索化初始化流程 10_线索化_遍历思想 11_线索化_遍历树时,把结点插入链表中 12_中午课程总结和线索化逆序访问 13_霍夫曼树概念 14_排序_概念 15_排序_选择法 16_排序_插入法 17_排序_冒泡 18_排序_希尔排序 19_排序_希尔排序_分组很重要 20_排序_快速排序 21_排序_归并 22_数据结构课程_知识体系梳理 代码 文档 01_上一次课程知识点回顾 02_递归需要需要掌握的点补充 03_链表类_链式存储_测试 04_链表类_链式存储_api实现 05_链表类_链式存储_课堂答疑 06_栈类_链式存储_api实现 07_队列类_链式存储设计与实现_api 08_链表类_顺序存储_类设计和测试框架 09_链表类_顺序存储_类api实现 10_栈类_顺序存储_实现 11_队列类_顺序存储设计与实现 c++基础串讲复习1 c++基础串讲复习2 c++基础串讲复习3 c++基础串讲复习4 c++基础串讲复习5 代码 数据结构书籍和工具收集 文档 第5部分 C_C++与设计模式基础 01_设计模式课程安排和要求 02_UML的建模和基本概念 03_UML图_用例图_基础 04_UML图_用例图_人事管理系统案例_传扫地 05_UML图_类图_基础和类关系依赖 06_UML图_类图_关联_聚合_组合_传扫地 07_UML图_时序图_传扫地 08_UML图_活动图_传扫地 09_UML图_状态图_进程状态案例 10_UML图_协作图_包图_部署图 11_设计模式_概念和设计原则 12_中午课程回顾 13_设计模式基本原则_依赖倒转 14_设计模式基本_依赖倒置和迪米特法则 15_单例模式_懒汉式和饿汉式 16_懒汉式遇上多线程问题 17_懒汉式多线程同步优化 18_简单工厂模式 19_工厂模式_传扫地 文档 源码 01_上一次课程知识点梳理 02_抽象工厂模式 03_抽象工厂课堂答疑 04_建造者模式_理论模型 05_建造者模式_实现 06_建造者模式_问题抛 07_原型模式 08_建造模式总结 09_课堂交流从建造者模式说开去 10_厚积薄发话题 11_代理模式_传扫地 12_装饰模式_传扫地 13_中午课程回顾 14_适配器模式 15_桥接模式_理论模型 16_桥接模式_实现_传扫地 17_组合模式_上 18_组合模式_下 19_外观模式 20_享元模式 文档 源码 01_设计模式知识体系梳理01 02_模板模式_传扫地 03_命令模式_技术推演上 04_命令模式_技术推演下_传扫地 05_责任链模式 06_策略模式_及题外话 07_策略模式_实现 08_中介者模式_问题抛上 09_中介者模式_实现下 10_中午知识点回顾 11_观察者模式_传扫地 12_备忘录模式 13_访问者模式_概念基本原理_案例了解 14_访问者模式_实现_传扫地 15_状态模式_原理及代码串讲 16_解释器模式 17_迭代器模式_思想_传扫地 18_迭代器模式_实现_传扫地 19_设计模式知识体系梳理02 文档 源码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值