I've seen similar questions, but not quite like the predicament I find myself in. I'm working with someone else's code, and their structure is like this.
//db_manager.h
class db_manager
{
class error;
bool logError(error::def_enum::Value v, string msg);
bool read(int id);
}
//db_manager.cpp
#include db_manager.h
bool logError(error::def_enum::Value v, string msg)
{
return error::logError(v, msg);
}
bool read(int id)
{
//do db access stuff
return true;
}
//error.h
#include db_manager
class error
{
bool read(int id);
}
//error.cpp
#include error.h
bool read(int id)
{
return db_manager::read(id);
}
bool logError(error::def_enum::Value v, string msg)
{
//do error service stuff
}
This is a pretty obvious simplification, but hopefully it demonstrates the issue.
When I compile, I get a lot of incomplete type errors whenever error is used in db_manager.cpp, and I can't include the relevant header files from error into db_manager.cpp, because then I have to add it to db_managers cmake dependencies, which means I have to list it in package.xml, and then it gets upset from the circular dependency. How can I get around this? If I could use error's members in db_manager without making error a dependency, I'd be good, I think, but I just can't figure out how to do that. I've seen many other forward-declaration questions on here, but for all of them, the declared class usage isn't very deep. Here I'm using class members, not just declaring a class pointer like other questions.
I definitely could use help, I just don't see any logical way to do this without completely scrapping the error package and writing a new one.
Edit: also, I simplified this out, but maybe I shouldn't have. error and db_manager are in two separate packages.
First: Your example is very bad. Please provide a minimum working example. I understand what your problem is (circular dependency), but your example is not showing this Problem. This is something you have to solve on an architectural level. You can't solve this inside CMake.
Depending on the Code you have shown you don't need to include db_manager.h in error.h, since you are not using anything from db_manager during the declaration of class Error. You only need to include it inside error.cpp, since there you are using one static method from db_manager. That way you don't have any circular dependency.
I have added a minimum working example below which compiles without any errors.
error.h
#ifndef _ERROR_H_
#define _ERROR_H_
#include <string>
class Error
{
public:
enum def_enum{ Val1, Val2};
bool read(int id);
static bool logError(def_enum v, std::string msg);
};
#endif /* _ERROR_H_ */
error.cpp
#include "error.h"
#include "db_manager.h"
bool Error::read(int id)
{
return db_manager::read(id);
}
bool Error::logError(Error::def_enum v, std::string msg)
{
//do error service stuff
return true;
}
db_manager.h
#ifndef _DB_MANAGER_H_
#define _DB_MANAGER_H_
#include <string>
#include "error.h"
class db_manager
{
public:
static bool logError(Error::def_enum v, std::string msg);
static bool read(int id);
};
#endif /* _DB_MANAGER_H_ */
db_manager.cpp
#include "db_manager.h"
bool db_manager::logError(Error::def_enum v, std::string msg)
{
return Error::logError(v, msg);
}
bool db_manager::read(int id)
{
//do db access stuff
return true;
}
main.cpp
#include "db_manager.h"
#include "error.h"
int main(){
db_manager::read(1);
db_manager::logError(Error::Val1, "Test");
Error e;
e.read(2);
return 0;
}
CMakeLists.txt
project(db_manager)
add_executable(executable main.cpp db_manager.cpp error.cpp)
Related
I've done this so many times, yet the reason why Visual Studio is complaining about this escapes me.
Manipulator.cpp:
#include "Manipulator.h"
Manipulator::Manipulator() {}
Manipulator::~Manipulator() {}
void proc(std::string p, int f, std::string c)
{
// switch-case p to c based on f:
return;
}
Manipulator.h: (void -proc- has a curly underscore, and that's what's driving me up the wall.)
#ifndef MANIPULATOR_H
#define MANIPULATOR_H
#include <string>
class Manipulator
{
private:
protected:
public:
Manipulator() ;
~Manipulator() ;
void proc(std::string, int, std::string);
// function definition for 'proc' not found.
};
#endif MANIPULATOR_H
main.cpp
#include "Manipulator.h"
...
int main()
{
...
Manipulator m;
...
m.proc(opdBMP, fxn, newBMP);
return 0;
}
What is it that VS wants so that I can get a move on? It is telling me that there are two linker errors: LNK2019 and LNK1120 (unresolved external). (I used to keep track of these kinds of errors but lost the file as a log with these.)
The compiler is correct in complaining, because the definition should be
void Manipulator::proc(std::string p, int f, std::string c) {
...
}
You just defined a free function instead of a member of Manipulator.
I have a problem with a following code:
#ifndef HEADER_H_
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
#endif
//include libraries
#include "Header.h"
using namespace std;
int main()
{
vector <SelectorBox> vectorSelectBox;
SelectorBox *selectorBox;
//code
return 0;
}
#include "Header.h"
#include "main.cpp"
void SelectorBox::setSelectorName(string name) //setter
{
name = trimTheString(name);
selectorName = name;
}
void SelectorBox::setAttribute(string key, string value) //setter
{
key = trimTheString(key);
value = trimTheString(value);
attributeMap[key] = value;
}
When I compile a program, it shows many errors (specifically errors 4430 and 2061), but I believe that the main error is:
error C2011: 'SelectorBox' : 'class' type redefinition.
You must define HEADER_H_. You missed second line from below code.
#ifndef HEADER_H_
#define HEADER_H_
...
#endif
You are including the same header twice, first before main second after main, this causes a problem if you don't use proper include guards.
Your include guard is incomplete, so multiple includes of the same header will cause this error. The trick is to check if a header-specific preprocessor name is defined: If not, then define it, else skip the whole header.
The pattern to use is like this
#ifndef GUARD
#define GUARD
/// the actual header contents
#endif
but simply copying it into every header will cause another problem, because its lack of header specificity. The simplest way to find a good name is to derive it from the file name itself. In your case I'd name the header after the class SelectorBox defined in it, so SelectorBox.h would be a good name, and the include guards would look like this:
#ifndef SELECTORBOX_H
#define SELECTORBOX_H
class SelectorBox {
/// etc.
};
#endif
Using multiple headers with the same include guard is much worse than using no include guards at all.
I guess, you have 3 files:
Header.h
main.cpp
FileX.cpp (you didn't disclose the real name of mister X so far)
In main.cpp you are including Header.h, in FileX.cpp you are including Header.h and main.cpp. Let me show a simplified version of what happens here:
The contents of main.cpp gets transformed into
//include libraries
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
using namespace std;
int main()
{
vector <SelectorBox> vectorSelectBox;
SelectorBox *selectorBox;
//code
return 0;
}
Assuming you included string and map and there is another using namespace std; somewhere before your class definition, this could compile without errors.
But now let's see what happens in FileX.cpp. Its contents gets transformed into the following, and I hope you'll see now what the compilers sees: there is more than one definition of the class SelectorBox:
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
//include libraries
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
using namespace std;
int main()
{
vector <SelectorBox> vectorSelectBox;
SelectorBox *selectorBox;
//code
return 0;
}
void SelectorBox::setSelectorName(string name) //setter
{
name = trimTheString(name);
selectorName = name;
}
void SelectorBox::setAttribute(string key, string value) //setter
{
key = trimTheString(key);
value = trimTheString(value);
attributeMap[key] = value;
}
... compilers use to call that a "redefinition".
I'm having difficulty interpreting some of my results, which I would expect to behave the same but are not.
I am trying to write a method that returns a function pointer getPtrFn
I have a main.c file reading
#include <iostream>
#include "test.hpp"
int main(int argc, char* argv[]){
Test test;
void (*fPtr)(void) = test.getPtrFn();
return 0;
}
A test.hpp file that reads
#ifndef _test_h
#define _test_h
class Test {
private:
void (*ptrFn)(void);
public:
Test(){};
void (*getPtrFn(void))(void){
return ptrFn;
};
~Test();
};
#endif
And a test.cpp file that reads
#include "test.hpp"
Test::~Test(){}
This runs fine. However, when I move the implementation for *getPtrFn(void) to the implementation file (revised files shown below),
test.hpp:
#ifndef _test_h
#define _test_h
class Test {
private:
void (*ptrFn)(void);
public:
Test(){};
void (*getPtrFn(void))(void);
~Test();
};
#endif
test.cpp:
#include "test.hpp"
void (Test::*getPtrFn)(void){
return ptrFn;
};
Test::~Test(){}
I get the compile error
test.cpp:16:9: error: use of undeclared identifier 'ptrFn'
My understanding of the language syntax is that they would be treated the same. So what gives?
-Jeff
You need
void(*Test::getPtrFn(void))(void)
{
return ptrFn;
}
instead of void (Test::*getPtrFn)(void){...}. void (Test::*getPtrFn)(void) is the declaration of getPtrFn as a pointer-to-Test-member-function taking no parameters (void) and returning void, so after you put the braces { ... } you get a compile-time error (its like trying to declare int i{/*some statemets*/}).
Also, and don't forget to keep the declaration
void(*getPtrFn(void))(void);
in your header (right now it seems you don't have it, did you cut/pasted it?).
Quite a horrible thing to look at... So really, use a type alias, it makes your code much cleaner.
using PTRFN = void(*)(void); // or typedef void(*PTRFN)(void);
class Test {
private:
PTRFN ptrFn;
public:
PTRFN getPtrFn(void);
Test(){};
~Test(){};
};
PTRFN Test::getPtrFn(void) // clear an concise
{
return ptrFn;
}
In case you really really want to be able do decipher every kind of pointer declaration you can think of, try looking at the clockwise/spiral rule, I found it extremely useful, clear and easy to understand. Then test your knowledge at cdecl.org.
I have many .cpp files in my project that work. But this one irritates Xcode or the compiler.
It doesn't recognise free() and malloc() but this is also C. What can be wrong?
Header ssdpmessage.h looks like this:
#ifndef _SSDPMESSAGE_H
#define _SSDPMESSAGE_H
#include "ssdptools.h"
#include <vector>
#include <arpa/inet.h>
#include "ssdpdb.h"
class SSDPMessage{
public:
SSDPMessage();
virtual ~SSDPMessage();
//What type of message can we handle
virtual SSDP_TYPE GetType()=0;
//Get the message dignature implemented in this class
virtual std::vector<SSDP_HTTP_HEADER*> GetHeaderSignature();
//Can this class parse the message with this signature ?
virtual u8 CanProcess(std::vector<SSDP_HTTP_HEADER*> msgheaders);
//Process the message, return value:
//0 : processed
//1 : not for me, search for another to process
//<0 : message was for me but there is an error
virtual int Process(struct sockaddr* sender, std::vector<SSDP_HTTP_HEADER*> msgheaders)=0;
//ReInit all members
virtual void ReInit()=0;
virtual SSDPDB* GetDB();
virtual void SetDB(SSDPDB* db);
private:
std::vector<SSDP_HTTP_HEADER*> mHeaderSignature;
protected:
int AddSignatureHeader(char* fieldname, char* fieldvalue);
SSDPDB *mDB;
private:
SSDPMessage(const SSDPMessage &src);
SSDPMessage& operator= (const SSDPMessage &src);
};
#endif //_SSDPMESSAGE_H
The includes and affected code in ssdpmessage.cpp look like this:
#include "ssdpmessage.h"
SSDPMessage::SSDPMessage():mDB(NULL){
}
SSDPMessage::~SSDPMessage(){
std::vector<SSDP_HTTP_HEADER*>::iterator it;
for(it=mHeaderSignature.begin(); it<mHeaderSignature.end(); it++){
free(*it);
}
mHeaderSignature.clear();
}
int SSDPMessage::AddSignatureHeader(char* fieldname, char* fieldvalue){
SSDP_HTTP_HEADER *thisHeader = (SSDP_HTTP_HEADER*)malloc(sizeof(SSDP_HTTP_HEADER));
thisHeader->fieldname = (u8*)fieldname;
thisHeader->fieldnamelen = strlen(fieldname);
thisHeader->fieldvalue = (u8*)fieldvalue;
thisHeader->fieldvaluelen = strlen(fieldvalue);
mHeaderSignature.push_back(thisHeader);
return mHeaderSignature.size();
}
This is code from the upnpx library. It works without problem in the demo project of the library.
malloc requires you to include cstdlib.
I'm trying to crosscompile some porject in eclipse, but I'm getting a error which is driven me crazy. It has to be with the inclusions and libraries headers, in the picture it can be seen the project tree.
PICTURE
The issue is that I cannot understand why I the path I'm using is wrong for the compilation, any advice?
Thanks in advance,
This is the TestUtils.cpp where the inclusion gives error
#include "TestUtils.h"
#include <ibrdtn-0.8.0/utils/Utils.h> //sucks
CPPUNIT_TEST_SUITE_REGISTRATION (TestUtils);
void TestUtils::setUp()
{
}
void TestUtils::tearDown()
{
}
void TestUtils::tokenizeTest()
{
using namespace dtn::utils;
CPPUNIT_ASSERT(Utils::tokenize(":", "").empty());
CPPUNIT_ASSERT(Utils::tokenize(":", "::").empty());
CPPUNIT_ASSERT_EQUAL((int)Utils::tokenize(":", ":a:test::", 2).size(), 2);
CPPUNIT_ASSERT_EQUAL((int)Utils::tokenize(":", ":a:test::b::", 2).size(), 3);
//TODO how should the added string in the last item look like? "b::" or ":b::" or "::b::"
CPPUNIT_ASSERT(Utils::tokenize(":", ":a:test::b::", 2)[2] == "b::");
CPPUNIT_ASSERT_EQUAL((int)Utils::tokenize(":", ": :", 1).size(), 1);
CPPUNIT_ASSERT_EQUAL((int)Utils::tokenize(":", ": :t e s t: ").size(), 3);
}
The error is this
/tests/utils/TestUtils.cpp:10:38: warning: ibrdtn-0.8.0/utils/Utils.h: No such file or directory
And the Utils.h which does not seem to exist is this
#ifndef UTILS_H_
#define UTILS_H_
#include "ibrdtn/data/Bundle.h"
#include "ibrdtn/data/CustodySignalBlock.h"
#include "ibrdtn/data/StatusReportBlock.h"
#include "ibrdtn/data/PayloadBlock.h"
namespace dtn
{
namespace utils
{
class Utils
{
public:
static void rtrim(std::string &str);
static void ltrim(std::string &str);
static void trim(std::string &str);
static vector<string> tokenize(std::string token, std::string data, size_t max = std::string::npos);
static double distance(double lat1, double lon1, double lat2, double lon2);
static void encapsule(dtn::data::Bundle &capsule, const std::list<dtn::data::Bundle> &bundles);
static void decapsule(const dtn::data::Bundle &capsule, std::list<dtn::data::Bundle> &bundles);
private:
static void encapsule(ibrcommon::BLOB::Reference &ref, const std::list<dtn::data::Bundle> &bundles);
static double toRad(double value);
static const double pi;
};
}
}
#endif /*UTILS_H_*/
First problem, since it is not part of your includes being referenced by Eclipse, then it should be surrounded by quotations "" and not <>.
Second, your inclusion path is incorrect. There is a ibrtn subfolder
for which you are not taking account. So, instead of having the main parent folder, the inclusion path should be #include "ibrdtn/utils/Utils.h"
Fix those two items and you should be in business.