У меня есть проблема, связанная с анализом файла JSON. Он состоит из массива JSON объектов, и разработанная мною программа анализирует его, просто перебирая различные { ... }
элементы, найденные в файле.
Элементы (в файле JSON (это строки файла) структурированы таким образом, что внутри каждой строки могут быть другие внутренние элементы, но это выходит за рамки проблемы, с которой мне приходится сталкиваться.
Короче говоря, у меня есть Block
; внутри него у меня есть, помимо других полей, вектор Operations
, тип которого Operation
, и в этом векторе каждый элемент может иметь подтип Operation
, например, Vote
, Comment
, Follow
, Repost
, ...
Для этого я создал заголовок файла BlockStructure.hpp
, который включает определение класса Operation
вместе с (только) виртуальным метод print()
и определение классов, перечисленных ранее. В дополнение к этим определениям, есть также определение TransactionBlock
, Transaction
и BlockStructure
// BlockStructure.hpp
#include <string>
#include <list>
#include <utility>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
using ui = unsigned int;
class Operation{
public:
string kind = "";
virtual string print();
};
class Vote : public Operation {
private:
string voter, author;
public:
Vote(string voter, string author);
virtual string print();
string get_voter();
string get_author();
};
class Comment : Operation{
private:
string parent_author, author, title, body;
public:
Comment(string parent_author, string author, string title, string body);
string get_author();
virtual string print();
};
class Follow : Operation{
private:
string follower, following;
vector<string> common_follows{};
public:
CustomJsonFollow(string follower, string following, vector<string> common_follows);
static void strip(vector<string> *w); // implements the common strip function
static void stripLeadingAndtrailingSpaces(string *stng); // implements the strip by removing the whitespaces
string get_follower();
string get_following();
vector<string> get_common_follows();
virtual string print();
};
class Reblog : Operation{
private:
string account, author;
public:
CustomJsonReblog(string account, string author);
string get_account();
string get_author();
virtual string print();
};
class TransactionBlock{
private:
vector<Operation*> operations{};
string transaction_id;
int transaction_num = -1;
public:
TransactionBlock(vector<Operation*> ops);
TransactionBlock();
vector<Operation*> get_operations();
void set_operations(vector<Operation*> ops);
string get_transaction_id();
void set_transaction_id(string tid);
int get_transaction_num();
void set_transaction_num(int trn);
string print();
};
class Transaction{
private:
string transaction_id;
TransactionBlock transactionBlock;
public:
Transaction(string tr_id, TransactionBlock transactionBlock);
string get_transaction_id();
void set_transaction_id(string tid);
TransactionBlock get_transaction_block();
void set_transaction_block(TransactionBlock tbl);
void print();
};
class BlockStructure{
private:
list<Transaction> transactions{};
string timestamp;
list<int> transaction_ids;
TransactionBlock transactionBlock;
public:
BlockStructure();
void set_transactions(list<Transaction> transact);
void set_transaction_block(TransactionBlock transactBlock);
void set_timestamp(string ts);
void set_transaction_ids(list<int> tr_ids);
void set_transaction_block(const TransactionBlock& tb);
TransactionBlock get_transaction_block();
void print_block();
};
Впоследствии, в другом файле, называемом BlockStructure.cpp
, у меня есть реализация всех методы, определенные в заголовке, так:
// BlockStructure.cpp
#include "BlockStructure.hpp"
using namespace std;
using ui = unsigned int;
// Operation
string Operation::print(){
return "";
}
// Vote
Vote::Vote(string voter, string author) : voter(move(voter)), author(move(author)) { this->kind = "VOTE"; }
string Vote::print(){
string toret = "V\n";
toret += "voter: " + this->voter + "\n";
toret += "auth: " + this->author + "\n";
return toret;
}
string Vote::get_voter(){
return this->voter;
}
string Vote::get_author(){
return this->author;
}
// Comment
Comment::Comment(string parent_author, string author, string title, string body){
this->parent_author = move(parent_author);
this->author = move(author);
this->title = move(title);
this->body = move(body);
this->kind = "COMMENT";
}
string Comment::get_author(){
return this->author;
}
string Comment::print(){
string toret = "C\n";
toret += "par_auth: " + this->parent_author + "\n";
toret += "auth: " + this->author + "\n";
toret += "title: " + this->title + "\n";
toret += "body: " + this->body + "\n";
return toret;
}
// Follow
void Follow::strip(vector<string> *w) {
auto it = w->begin();
for (ui i = 0; i < w->size(); i++) {
stripLeadingAndtrailingSpaces(&(*it));
advance(it, 1);
}
}
void Follow::stripLeadingAndtrailingSpaces(string *stng) {
char *cur = const_cast<char *>(stng->c_str());
/* First remove leading spaces */
const char *firstNonSpace = cur;
while (*firstNonSpace != '\0' && isspace(*firstNonSpace))
++firstNonSpace;
size_t len = strlen(firstNonSpace) + 1;
memmove(cur, firstNonSpace, len);
/* Now remove trailing spaces */
char *endOfString = cur + len;
while (cur < endOfString && isspace(*endOfString))
--endOfString;
*endOfString = '\0';
}
Follow::Follow(string follower, string following, vector<string> common_follows, vector<string> required_posting_auths) {
this->follower = move(follower);
stripLeadingAndtrailingSpaces(&this->follower);
this->following = move(following);
stripLeadingAndtrailingSpaces(&this->following);
this->common_follows = move(common_follows);
strip(&this->common_follows);
this->kind = "FOLLOW";
}
string Follow::get_follower() {
return this->follower;
}
string Follow::get_following(){
return this->following;
}
vector<string> Follow::get_common_follows(){
return this->common_follows;
}
string Follow::print(){
string toret = "F\n";
toret += "follower: " + this->follower + "\n";
toret += "following: " + this->following + "\n";
if (!this->common_follows.empty()){
toret += "common_follows: \n";
for (const string& w : this->common_follows)
toret += w + "\n";
} else
toret += "common_follows: []\n";
return toret;
}
// Reblog
Reblog::Reblog(string account, string author){
this->account = move(account);
this->author = move(author);
this->kind = "REBLOG";
}
string Reblog::get_account(){
return this->account;
}
string Reblog::get_author(){
return this->author;
}
string Reblog::print(){
string toret = "RB\n";
toret += "account: " + this->account + "\n";
toret += "author: " + this->author + "\n";
return toret;
}
(и аналогично для TransactionBlock
, Transaction
и BlockStructure
)
Затем я включаю BlockStructure.hpp
внутри файла ParsingBlocks.cpp
, определенного в следующем. Файлы
"jsoncpp/dist/json/json.h"
"jsoncpp/dist/jsoncpp.cpp"
, которые я включаю в начале, являются результатом сценария python amalgamate.py
(этот сценарий также генерирует jsoncpp/dist/json/json-forward.h
, но я читал, что он обычно не используется для проектов) , Я читал, что это подход к интеграции JsonCpp в проект.
#include <fstream>
#include "jsoncpp/dist/json/json.h"
#include "jsoncpp/dist/jsoncpp.cpp"
#include "BlockStructure.hpp"
class ParsingBlocks {
private:
string path;
public:
ParsingBlocks(string path) : path(move(path)) {}
vector<Operation*> fill_ops(const Value& trans_operations){
vector<Operation*> op_array = {};
for(Value op : trans_operations) {
if (op[(UInt) 0].asString() == "vote") {
string voter = op[1]["voter"].asString();
Vote vt = Vote(op[1]["voter"].asString(), op[1]["author"].asString());
op_array.push_back((Operation*)&vt);
} else if (op[(UInt) 0].asString() == "comment") {
Comment cmt = Comment(op[1]["parent_author"].asString(),
op[1]["author"].asString(),
op[1]["title"].asString(),
op[1]["body"].asString());
op_array.push_back((Operation*)&cmt);
} else if (op[(UInt) 0].asString() == "custom_json") {
auto custom = op[(UInt) 1];
if (custom["id"].asString() == "follow") {
Value injs = custom["id"];
if (injs[(UInt) 0].asString() == "follow") {
vector<string> common_follows = {};
for (const auto &itr : injs[(UInt) 1]["common_follows"])
common_follows.push_back(itr.asString());
CustomJsonFollow follow = CustomJsonFollow(
injs[1]["follower"].asCString(),
injs[1]["following"].asCString(),
common_follows);
op_array.push_back((Operation*)&follow);
} else {
if (injs[(UInt) 0].asString() == "reblog") {
CustomJsonReblog reblog = CustomJsonReblog(
injs[(UInt) 1]["account"].asCString(),
injs[(UInt) 1]["author"].asCString());
op_array.push_back((Operation*)&reblog);
}
}
}
}
}
return op_array;
BlockStructure evaluate_block(const string& line){
ifstream ifs(line);
CharReaderBuilder reader;
Value data;
string errs;
Json::parseFromStream(reader, ifs, &data, &errs);
BlockStructure bs = BlockStructure();
for(Value::ArrayIndex i = 0; i != data.size(); i++){
bs.set_timestamp(data[i]["timestamp"].asString());
list<Transaction> transss{};
for(const Value& transaction : data[i]["transactions"]){
vector<Operation*> operations = fill_ops(transaction["operations"]);
auto t_block = new TransactionBlock();
t_block->set_transaction_num(transaction["transaction_num"].asInt());
if (!operations.empty()){
t_block->set_operations(operations);
}
Transaction t = Transaction(transaction["transaction_id"].asString(), *t_block);
transss.push_back(t);
}
bs.set_transactions(transss);
bs.set_witness_name(data[i]["witness"].asString());
}
return bs;
}
list<BlockStructure> parsing_blocks(){
string line;
ifstream file;
file.open(this->path);
list<BlockStructure> blocks{};
if(!file.is_open()){
perror("Error open");
exit(EXIT_FAILURE);
}
while (getline(file, line)){
BlockStructure b = evaluate_block(line);
blocks.push_back(b);
}
return blocks;
}
}
Оставляя в стороне возможные ошибки копирования и вставки (что, я думаю, я не сделал), теперь я использую ParsingBlocks.cpp
в main.cpp
, определенном следующим образом:
#include "ParsingBlocks.cpp"
using namespace std;
int main() {
ParsingBlocks *pb = new ParsingBlocks("jsonfile.json");
list<BlockStructure> blocks = pb->parsing_blocks();
for(BlockStructure bl : blocks){
bl.print_block();
}
return 0;
}
Я не показываю другой класс (UserStructure.cpp
), используемый в компиляции, потому что он бесполезен для целей вопрос.
Теперь моя проблема - понять, как скомпилировать файл main.cpp
.
Я полагаюсь на внешнюю библиотеку jsoncpp
, поэтому во время компиляции выполняю из команды введите следующую строку:
c++ -std=c++17 -Wall -pedantic -I. .\UserStructure.cpp .\BlockStructure.hpp .\BlockStructure.cpp .\ParsingBlocks.cpp .\main.cpp -o parsing.out
, где флаг -I.
используется для связи в текущем каталоге, jsoncpp.cpp
и json/json.h
, определенные в #include
s в начало файла ParsingBlock.cpp
, как показано выше.
Компиляция выдает мне следующие ошибки:
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x2b6): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x2e0): multiple definition of `Json::Features::all()'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x2e0): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x2fe): multiple definition of `Json::Features::strictMode()'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x2fe): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x32c): multiple definition of `Json::Reader::containsNewLine(char const*, char const*)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x32c): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x36e): multiple definition of `Json::Reader::Reader()'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x36e): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x36e): multiple definition of `Json::Reader::Reader()'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x36e): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x44a): multiple definition of `Json::Reader::Reader(Json::Features const&)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x44a): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x44a): multiple definition of `Json::Reader::Reader(Json::Features const&)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x44a): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x52a): multiple definition of `Json::Reader::parse(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> > const&, Json::Value&, bool)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x52a): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x5de): multiple definition of `Json::Reader::parse(std::istream&, Json::Value&, bool)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x5de): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x698): multiple definition of `Json::Reader::parse(char const*, char const*, Json::Value&, bool)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x698): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x934): multiple definition of `Json::Reader::readValue()'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x934): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x1032): multiple definition of `Json::Reader::skipCommentTokens(Json::Reader::Token&)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x1032): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x1086): multiple definition of `Json::Reader::readToken(Json::Reader::Token&)'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x1086): first defined here
C:\Users\Utente\AppData\Local\Temp\cc8uGWcY.o:main.cpp:(.text+0x1246): multiple definition of `Json::Reader::skipSpaces()'
C:\Users\Utente\AppData\Local\Temp\ccDGeveZ.o:ParsingBlocks.cpp:(.text+0x1246): first defined here
Итак, должно быть очевидно, что проблема в фазе компоновки , но я не могу решить это!
Я попытался, прочитав и документацию, и другие вопросы. o n stackoverflow.com, но я ничего не получаю.
Заранее спасибо за помощь, и я извиняюсь, если этот вопрос немного огромен.
РЕДАКТИРОВАТЬ: вывод stderr не остановитесь на этом: есть по крайней мере 1000 строк ошибок, но каждая из них относится к одному и тому же multiple definition of ..., C:...: first defined here
.