写在前面:在vs2015/2017编写代码,首先是新建工程:可以是空项目,然后就是配置release或者debug环境下的项目属性。
类的对象:用的是内存栈,是个局部的临时变量.
类的指针:用的是内存堆,是个永久变量,除非你释放它.
像一些日志类,就会声明类指针而不是类对象
引用的作用,由于引用传入的是地址,因此有时写的函数完全不需要返回值,直接把要返回的值放在形参中,用地址传进来。这样函数看起来会很简洁。
如下所示
#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;
};
可以说结构体和类一样,只不过结构体中定义的变量或者方法的默认访问属性是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) {}
};
对于多行函数,用\进行换号。
//行、列、图像头的长度
#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; \
} \
}
在结构体和类中是默认有字节对齐的,但是对于一些图片类,里面的信息可能有int 有char等等,按字节对齐可能有些信息为空。
如果想要取消,那么需要在结构体或类的前面和后面加入
#pragma pack(n)
代码块
#pragma pack()
n表示设置内存对齐为:n字节对齐。使用方法可以参考这里:#pragma pack(1) 的意义是什么
目的:软件更新发布的时候比较方便:
以下内容参考了:VS2015 C++ dll动态库的制作以及调用 和VS2019 制作并调用c++动态库步骤
//--------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;
}
点击生成,会发现报这个错误,这是因为我们创建的是一个win32空项目,但是并没有用到main等函数也没有窗口什么的。不过这不妨碍我们制作dll文件。会发现在release目录下已经生成了dll文件了。
接下就是使用动态库了,新建一个空项目,模式为release,首先先新建一个cpp文件,运行得到release目录。因为这里想采用导入动态库dll直接复制到EXE文件这个目录下。当然也可以配置环境变量或者放入system32中。将刚刚制作好的DLL1.dll复制到release目录下,将头文件lxdll.h和
DLL1.lib复制到程序目录里,然后在测试代码中引入头文件,引入lib库即可:
//------------测试的主函数
#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;
}
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容器中
}
}
大型项目中,往往需要传入许多参数,这时候我们通常会通过添加配置文件ini的方法传入,这也方便我们在外部对程序中的变量进行修改。
首先,我们可以在定义结构体类型,用于保存多种类型的数据。
然后在类中的protected:创建一个结构体类型的成员变量;
接着在public:或者protected:中设置一个readCfg()成员函数,用于初始化结构体成员变量。
如何在readCfg()函数中读配置参数?
可以利用GetPrivateProfileIntA函数和GetPrivateProfileStringA函数。
一个用于读取int类型,一个用于读取String类型。
以GetPrivateProfileIntA为例:
结构体.参数1 = ::GetPrivateProfileIntA(ini文件中要查找的条目小节, ini文件中要匹配的变量名, 默认返回参数, ini文件路径);
GetPrivateProfileStringA的使用可以参考这篇文章:GetPrivateProfileString使用 ,这篇文章还讲了读取写入的操作。
补充,如果想要在控制台打印,那么建议写一个日志。
最后
如果觉得对你有所帮助的话,希望能点赞收藏一波,您的鼓励就是对我最大的支持,谢谢!