C++中的经验记录

写在前面:在vs2015/2017编写代码,首先是新建工程:可以是空项目,然后就是配置release或者debug环境下的项目属性。

  • 在C/C++的常规中,设置附加包含目录
  • 连接器输入-------附加依赖项
  • 如果包含cuda编程,需要右键项目属性,生成依赖项—自定义勾选cuda

文章目录

      • 1、指针
      • 2、引用&
      • 3、结构体
      • 4、宏定义
      • 5、字节对齐
      • 6、制作动态库dll
      • 7、读取json对象
      • 8、读取ini配置文件

1、指针

类的对象:用的是内存栈,是个局部的临时变量.
类的指针:用的是内存堆,是个永久变量,除非你释放它.

像一些日志类,就会声明类指针而不是类对象

2、引用&

引用的作用,由于引用传入的是地址,因此有时写的函数完全不需要返回值,直接把要返回的值放在形参中,用地址传进来。这样函数看起来会很简洁。
如下所示

#pragma once
#include 
#include 
#include 
using namespace std;

class someThing
{
public:
	someThing();
	void ReadTxtData(const char* txtFileName, vector<int> &txtData);								  
	void initStone(const char* path, vector<int> &airData, vector<int> &emptyData, cv::Mat &dstImg);  
	void colCorrosion(cv::Mat &dstImg, float Ratio, cv::Mat &finalImg);			      

public:
	vector<int> air;     
	vector<int> empty;
	cv::Mat initImg;     
	cv::Mat finalImg;   
	float corrosionRatio = 0.2;  

};

3、结构体

可以说结构体和类一样,只不过结构体中定义的变量或者方法的默认访问属性是public的,而类是private的。

1、结构体在大型工程中经常会用到,因为它可以包含很多种数据类型,一般用于存储数据类型。
2、结构体可以有模板,有构造函数,也可以继承。

struct ColorImageInfo
{
	unsigned int rows;			//图像行数(高度)
	unsigned int cols;			//图像列数(宽度)
	unsigned int channels;		//图像通道
	unsigned int depth;			//图像位深(单位:字节)
	unsigned int size;			//图像大小

	__CV_CUDA_HOST_DEVICE__ ColorImageInfo():
		rows(0), cols(0), channels(0), depth(0), size(0){}
};
//下面是一个结构体模板,并且继承了上面的ColorImageInfo结构体
template<typename T>
struct ColorImageT : ColorImageInfo
{
	T* pDataB;		
	T* pDataG;			
	T* pDataR;	
	__CV_CUDA_HOST_DEVICE__ ColorImageT() : pDataB(nullptr), pDataG(nullptr), pDataR(nullptr) {}
};

4、宏定义

对于多行函数,用\进行换号。

//行、列、图像头的长度
#define CudaGlobal(rows, cols, headerLen)										\
int rowIndex = 0, colIndex = 0;													\
{																				\
	int blockRow = blockIdx.y;													\
	int blockCol = blockIdx.x;													\
	int threadRow = threadIdx.y;												\
	int threadCol = threadIdx.x;												\
	rowIndex = blockRow * blockDim.y + threadRow;								\
	colIndex = blockCol * blockDim.x + threadCol;								\
	if (rowIndex >= rows || colIndex >= cols || colIndex < headerLen)			\
	{																			\
		return;																	\
	}																			\
}

5、字节对齐

在结构体和类中是默认有字节对齐的,但是对于一些图片类,里面的信息可能有int 有char等等,按字节对齐可能有些信息为空。
如果想要取消,那么需要在结构体或类的前面和后面加入

#pragma pack(n)
代码块
#pragma pack()

n表示设置内存对齐为:n字节对齐。使用方法可以参考这里:#pragma pack(1) 的意义是什么

6、制作动态库dll

目的:软件更新发布的时候比较方便:
以下内容参考了:VS2015 C++ dll动态库的制作以及调用 和VS2019 制作并调用c++动态库步骤

  • 创建一个空项目
  • 创建lxdll.h和lxdll.cpp文件,文件中的代码分别为
//--------lxdll.h-------------
#pragma once
//动态库导出函数的声明
_declspec(dllexport) char* getName(char* name);

//--------lxdll.cpp-------------

#include
#include"lxdll.h"
using namespace std;
//函数的实现
char* getName(char* name)
{
	return name;
}

  • 修改项目配置属性(release模式),选择DLL,如下图所示
    C++中的经验记录_第1张图片

  • 点击生成,会发现报这个错误,这是因为我们创建的是一个win32空项目,但是并没有用到main等函数也没有窗口什么的。不过这不妨碍我们制作dll文件。会发现在release目录下已经生成了dll文件了。
    C++中的经验记录_第2张图片
    C++中的经验记录_第3张图片

  • 接下就是使用动态库了,新建一个空项目,模式为release,首先先新建一个cpp文件,运行得到release目录。因为这里想采用导入动态库dll直接复制到EXE文件这个目录下。当然也可以配置环境变量或者放入system32中。将刚刚制作好的DLL1.dll复制到release目录下,将头文件lxdll.h和
    DLL1.lib复制到程序目录里,然后在测试代码中引入头文件,引入lib库即可:
    C++中的经验记录_第4张图片
    C++中的经验记录_第5张图片

//------------测试的主函数
#include
#include"lxdll.h"     //dll库头文件
#pragma comment(lib, "DLL1.lib")      // 告诉程序lib文件的路径,这里就表示当前目录

using namespace std;
int main()
{
	//调用dll库函数
	char* myname = getName("huanhuncao");
	cout << myname << endl;
	system("pause");
	return 0;
}

运行效果如下:
C++中的经验记录_第6张图片

7、读取json对象

以下图为例,我需要在C++程序中读取json对象,
C++中的经验记录_第7张图片

	Json::Reader reader;	// 解析json用Json::Reader   
	Json::Value root;		// reader将Json字符串解析到root,root将包含Json里所有子元素 
	std::ifstream is;
	is.open(m_Stone_CategoryCfgPath, std::ifstream::in | std::ifstream::binary);   //其中m_Stone_CategoryCfgPath表示json文件所在的路径
	if (!is)
	{
		printf("读取./路径/stoneCategory.json数据失败");
	}
	std::vector<std::string> Dir;           //保存多分类文件夹名称的容器
	if (reader.parse(is, root))  			// reader将Json字符串解析到root,root将包含Json里所有子元素   
	{
		Json::Value::Members members;
		members = root.getMemberNames();    //获取key的成员数量
		for (Json::Value::Members::iterator iterMember = members.begin(); iterMember != members.end(); iterMember++)   // 用指针遍历每个key
		{
			std::string strKey = *iterMember;
			std::string temp = root[strKey.c_str()].asString();    //找到key对应的value
			std::string tempDir = stoneImageSaveDir + "/" + temp;   //进行目录拼接
			Dir.push_back(tempDir);                                //保存到vector容器中
		}
	}

8、读取ini配置文件

大型项目中,往往需要传入许多参数,这时候我们通常会通过添加配置文件ini的方法传入,这也方便我们在外部对程序中的变量进行修改。

首先,我们可以在定义结构体类型,用于保存多种类型的数据。
然后在类中的protected:创建一个结构体类型的成员变量;
接着在public:或者protected:中设置一个readCfg()成员函数,用于初始化结构体成员变量。

如何在readCfg()函数中读配置参数?

可以利用GetPrivateProfileIntA函数和GetPrivateProfileStringA函数。
一个用于读取int类型,一个用于读取String类型。

以GetPrivateProfileIntA为例:

结构体.参数1 = ::GetPrivateProfileIntA(ini文件中要查找的条目小节, ini文件中要匹配的变量名, 默认返回参数, ini文件路径);

GetPrivateProfileStringA的使用可以参考这篇文章:GetPrivateProfileString使用 ,这篇文章还讲了读取写入的操作。

补充,如果想要在控制台打印,那么建议写一个日志。

最后
如果觉得对你有所帮助的话,希望能点赞收藏一波,您的鼓励就是对我最大的支持,谢谢!

你可能感兴趣的:(C++,c++,算法,开发语言)