我把问题战略性地留在评论中,因为我认为用这种方式回答问题更容易。
基本上,我的小类所做的就是抽象出最初在函数中的功能。
这个类读取json格式的文件,并创建一个可以用来遍历json的对象。我明白,如果某件事可以变成一个函数,它不应该变成一个类,但我需要练习。
下面我概述了我要找的东西。选择一个或者全部选择。
寻找:
#include头文件Root rate("test.json", ["query"]["results"]["rate"]) (语法可以不同)不寻找(至少还没有):
#ifndef ROOT_H
#define ROOT_H
// Should header files always be included in root.h as opposed to root.cpp?
#include <fstream>
#include <string> // Seems like I do not need to include this string container, why?
//is it because json/json.h contains it?
#include "json/json.h" // Would I ever create a class with a dependency like this one?
// jsoncpp.sourceforge.net/annotated.html
class Root
{
private:
std::ifstream m_json;
public:
Json::Value m_root;
Json::Value m_query;
Root(const std::string&);
~Root();
};
#endif // ROOT_H#include "root.h"
Root::Root(const std::string & filename) : m_json(filename, std::ifstream::binary)
// Is std::ifstream::binary ok to put it in here like this ^?
// It's working, but would that be good practice?
{
m_json >> m_root;
m_json.close(); // Do I need .close() here?
}
Root::~Root(){}#include <iostream>
#include "root.h"
int main()
{
Root rate("test.json");
rate.m_query = rate.m_root["query"]["items"]; // Is it ok to assign member to a member like so,
// as opposed to just a variable?
// How can I instantiate my object like the line below?
// Root rate("test.json", ["query"]["results"]["rate"]);
// Syntax does not have to match precisely?
for(const auto & it : rate.m_query)
{
std::cout << it << std::endl;
}
}{
"query": {
"count": 3,
"items": [
{"item": "4"},
{"item": "3"},
{"item": "2"}
]
}发布于 2016-03-11 21:53:27
//应该始终将头文件包含在root.h中,而不是
您应该包含所需的所有头文件(不超过所需)。
在您的示例中,您将在头文件中使用以下类型。
std::ifstream
std::string
Json::Value因此,您应该为这些类型包括适当的头文件。
#include <fstream>
#include <string>
#include "json/json.h"唯一的曲线球是,如果您只使用类型引用,那么从技术上讲,您可以使用前向声明(而不是包含头文件)。所以您可以使用std::string的前向声明,不幸的是,它不是您的类,而且您实际上不知道如何转发声明它,因为这不是在标准中定义的,所以您必须包含头文件。
//似乎不需要包含这个字符串容器,为什么?
它可以通过<fstream>或"json/json.h"间接包括在内。但是您仍然应该包含<string>头文件,因为这些依赖项可能并不总是有效的(在不同的平台或编译器的不同版本上,它可能包含不同的内容)。因此,不要假设因为它在这个平台上工作,它将始终工作。考虑最坏的情况并显式地包括<string>
“包含保护”似乎有点过于通用:
ROOT_H看来其他人可能会用这个。你需要确保你的卫兵是独一无二的。我总是使用包含名称空间的警卫。
// I own the domain name thorsanvil.com
// and I put all my classes in the namespace ThorsAnvil
// So my include guards go like this.
#define THORSANVIL_<Optional Nested Namespace>_ROOT_H// std::ifstream::binary是否可以像^这样把它放在这里? //它起作用了,但这是一个好做法吗?
好的。完全没问题。
您只需理解它的含义以及二进制模式和文本模式(默认模式)之间的区别。在文本模式下:=>“特定于平台的”“行尾序列”在读取文件时被转换为'\n'。在二进制模式下:不执行转换,您将得到原始字节。
因此,在构造函数中:
Root::Root(const std::string & filename) : m_json(filename, std::ifstream::binary)
{
m_json >> m_root;
m_json.close(); // Do I need .close() here?
// Yes probably.
// Closing it releases the related OS resources.
// If you don't the resource will be held until
// the whole object is destroyed.
}我不认为m_json对象需要成为该对象的一部分。它只会在构造函数中使用。一旦加载了数据,就不会再使用它了。因此,只需将其声明为构造函数的本地自动变量即可。
Root::Root(const std::string & filename)
{
std::ifstream m_json(filename, std::ifstream::binary)
m_json >> m_root;
}
// Now we don't need `close()` because the object goes out of scope
// and the `std::ifstream` destructor calls close for us.//是否可以将成员分配给这样的成员,即 //,而不仅仅是变量?
它是。但为什么。使用局部变量似乎更符合逻辑。
Json::Value query = rate.m_root["query"]["items"];'\n'而不是std::endl不同之处在于,std::endl强制缓冲区刷新。缓冲区需要时会自动刷新。强迫它刷新只会使您的代码效率低下。
//如何像下面的行那样实例化我的对象? //根率(“test.json”,“查询”“费率”);
您可以定义operator[]。你可以用一个字符串作为参数。
class Root
{
public:
JsonValue operator[](std::string const& index)
{
return m_root[index];
}
// Other stuff in your class.
};现在,它可以用于:
Root json("file.name");
Json::Value = json["query"]["results"]["rate"];https://codereview.stackexchange.com/questions/122602
复制相似问题