使用jsoncpp库时的链接问题
Linking problem when using jsoncpp library
我在解析 JSON 文件时遇到问题。它由 JSON objects 数组组成,我开发的程序通过迭代文件中找到的各种 { ... }
元素来解析它。
元素(在 JSON 文件中,这些是文件的行)的结构使得每一行内可以有其他内部元素,但这超出了我遇到的问题现在处理。
总之,我有一个Block
;在其中,除了其他字段外,我还有一个类型为 Operation
的向量 Operations
,在该向量中,每个元素都可以是 Operation
的子类型,因此例如 Vote
、Comment
、Follow
、Repost
、...
为了处理这个问题,我创建了一个 BlockStructure.hpp
文件 header,其中包含 class Operation
的定义以及(唯一的)虚拟方法print()
和前面列出的 classes 的定义。除了这些定义之外,还有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
的文件中,我实现了 header 中定义的所有方法,因此:
// 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 != '[=11=]' && 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 = '[=11=]';
}
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;
}
}
抛开可能的 copy-and-paste 错误(我认为我没有做过),现在,我使用 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;
}
我没有展示编译中使用的另一个 class (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.
标志用于当前目录中的link,jsoncpp.cpp
和json/json.h
开头定义的#include
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
所以,应该很明显问题在linking阶段,但我无法解决!
我已经尝试阅读 whosebug.com 上的文档和其他问题,但我一无所获。
在此先感谢您的帮助,如果这个问题有点大,我很抱歉。
编辑:stderr 输出不止于此:至少有 1000 行错误,但每一行都认为相同 multiple definition of ..., C:...: first defined here
.
在主文件而不是源文件中包含头文件:
#include "ParsingBlocks.hpp"
C 和 C++ 中的 #include
不像许多其他语言那样是基于模块的包含,而是直接插入文件的文本。这意味着 ParsingBlocks.cpp
中的所有内容都被编译器读取了两次:一次是在编译主文件时,一次是在编译 ParsingBlocks.cpp
本身时,因此是重复项。
此外,您不需要在编译器命令行中指定头文件。
您刚刚包含了一个 cpp 文件。只应包含头文件。
通过包含 cpp 文件,编译器试图多次定义方法。
这基本上就是头文件存在的原因。
您保留 #include
ing 源文件("ParsingBlocks.cpp" 和 "jsoncpp/dist/jsoncpp.cpp")。
不要那样做。
它导致定义在你的最终程序中存在多次。
您的 main.cpp 应该 #include "ParsingBlocks.h"
以便它可以访问事物的 声明 。
并且您应该 编译并 link jsoncpp/dist/jsoncpp.cpp
到构建工具中的可执行文件中,就像其他 cpp
文件一样:
c++ -std=c++17 -Wall -pedantic -I. \
UserStructure.cpp \
BlockStructure.cpp \
ParsingBlocks.cpp \
main.cpp \
jsoncpp/dist/jsoncpp.cpp \
-o parsing.out
反斜线换行是为了清晰起见,这样我们可以更轻松地阅读命令。
请注意,我还删除了您在头文件中对 link 的尝试。
有关如何构建程序的更多信息,请参阅您的 C++ 书籍。
我在解析 JSON 文件时遇到问题。它由 JSON objects 数组组成,我开发的程序通过迭代文件中找到的各种 { ... }
元素来解析它。
元素(在 JSON 文件中,这些是文件的行)的结构使得每一行内可以有其他内部元素,但这超出了我遇到的问题现在处理。
总之,我有一个Block
;在其中,除了其他字段外,我还有一个类型为 Operation
的向量 Operations
,在该向量中,每个元素都可以是 Operation
的子类型,因此例如 Vote
、Comment
、Follow
、Repost
、...
为了处理这个问题,我创建了一个 BlockStructure.hpp
文件 header,其中包含 class Operation
的定义以及(唯一的)虚拟方法print()
和前面列出的 classes 的定义。除了这些定义之外,还有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
的文件中,我实现了 header 中定义的所有方法,因此:
// 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 != '[=11=]' && 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 = '[=11=]';
}
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;
}
}
抛开可能的 copy-and-paste 错误(我认为我没有做过),现在,我使用 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;
}
我没有展示编译中使用的另一个 class (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.
标志用于当前目录中的link,jsoncpp.cpp
和json/json.h
开头定义的#include
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
所以,应该很明显问题在linking阶段,但我无法解决!
我已经尝试阅读 whosebug.com 上的文档和其他问题,但我一无所获。
在此先感谢您的帮助,如果这个问题有点大,我很抱歉。
编辑:stderr 输出不止于此:至少有 1000 行错误,但每一行都认为相同 multiple definition of ..., C:...: first defined here
.
在主文件而不是源文件中包含头文件:
#include "ParsingBlocks.hpp"
C 和 C++ 中的 #include
不像许多其他语言那样是基于模块的包含,而是直接插入文件的文本。这意味着 ParsingBlocks.cpp
中的所有内容都被编译器读取了两次:一次是在编译主文件时,一次是在编译 ParsingBlocks.cpp
本身时,因此是重复项。
此外,您不需要在编译器命令行中指定头文件。
您刚刚包含了一个 cpp 文件。只应包含头文件。 通过包含 cpp 文件,编译器试图多次定义方法。 这基本上就是头文件存在的原因。
您保留 #include
ing 源文件("ParsingBlocks.cpp" 和 "jsoncpp/dist/jsoncpp.cpp")。
不要那样做。
它导致定义在你的最终程序中存在多次。
您的 main.cpp 应该 #include "ParsingBlocks.h"
以便它可以访问事物的 声明 。
并且您应该 编译并 link jsoncpp/dist/jsoncpp.cpp
到构建工具中的可执行文件中,就像其他 cpp
文件一样:
c++ -std=c++17 -Wall -pedantic -I. \
UserStructure.cpp \
BlockStructure.cpp \
ParsingBlocks.cpp \
main.cpp \
jsoncpp/dist/jsoncpp.cpp \
-o parsing.out
反斜线换行是为了清晰起见,这样我们可以更轻松地阅读命令。
请注意,我还删除了您在头文件中对 link 的尝试。
有关如何构建程序的更多信息,请参阅您的 C++ 书籍。