I have a code structure like this
myobj.h
#pragma once
struct myobj {
myobj();
...
} Myobj;
myobj.cpp
#include "myobj.h"
myobj::myobj() { ... }
...
mysketch.ino
#include "myobj.h"
Myobj.someMethod();
...
I understand this won't work because Arduino IDE compiles each file separatedly, so #pragma once won't help me to avoid the multiple definition error (Myobj was created twice) in the linking phase.
I'd like not to bother the user of my future library to create the global object by himself (the object will be used as singleton anyway). The working idea was to use macro:
myobj.h
#pragma once
struct myobj {
myobj();
...
};
#ifndef _MYOBJ_
myobj Myobj;
#endif
myobj.cpp
#define _MYOBJ_
#include "myobj.h"
myobj::myobj() { ... }
...
But then I have to remember to define this macro everywhere but in the ino file. It would be nice to detect that the myobj.h is included in the .ino file with setup and loop function. Is such detection possible without adding any extra code in that ino file? Is there any other way to define global object in library?
When I look into other libraries (like Servo), global object is created in the ino example. I can live with that, but there are objects like Serial that is auto-created somehow, I wonder how.
Ah, I found the solution in the SD library: one clever extern keyword!
myobj.h
#pragma once
struct myobj {
myobj();
...
};
extern myobj Myobj;
myobj.cpp
#include "myobj.h"
myobj::myobj() { ... }
...
myobj Myobj;
mysketch.ino
#include "myobj.h"
Myobj.someMethod(); // works, no multiple definition error
...
Related
I wrote some functions and create dll by C++ codes & used some of the C++ header files. But I found loadlibrary only supports C header files and I get this error:
Error using loadlibrary (line 419)
Failed to preprocess the input file.
Output from preprocessor is:LargeBaseConvertorClass.h
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\eh.h(26) : fatal error C1189: #error : "eh.h is only for
C++!"
I dont want to change my codes and I dont want to use mex functions.
How can I use my C++ dll in matlab? (I need a lot)
Thanks.
Ya Ali.
I've done two things to handle this before.
The first is to write a C wrapper around the C++ code.
//foo_c_wrapper.h
#ifndef FOO_C_WRAPPER_H
#define FOO_C_WRAPPER_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void* FOO_HANDLE;//can use a predeclared pointer type instead
FOO_HANDLE init_foo(int a);
void bar(FOO_HANDLE handle);
void destroy_foo(FOO_HANDLE** handle);
//ect
#endif
//foo.hpp
#ifndef FOO_HPP
#define FOO_HPP
class Foo {public: Foo(int); ~Foo(); void bar();}
#ifdef __cplusplus
}
#endif
#endif
//foo_c_wrapper.cpp
#include "foo_c_wrapper.h"
#include "foo.hpp"
extern "C" {
FOO_HANDLE init_foo(int a) {return new Foo(a);}
void bar(FOO_HANLDE handle) {
Foo* foo = reinterpret_cast<Foo*>(handle);
foo->bar();
}
void destroy_foo(FOO_HANDLE** handle) {
Foo** foo = reinterpret_cast<Foo**>(handle);
delete *foo;
*foo = NULL;
}
}
The other option is to go the rout of creating a custom mex file. Unfortunately that topic is way too broad to go into details here, so I'm going to count "Creating a C++ compatable Mex File" as the summary of the following link:
http://www.mathworks.com/help/matlab/matlab_external/c-mex-file-examples.html#btgcjh1-14
I did that in the past by creating a a few C interface functions to create and manipulate the C++ objects. Doing this makes it possible to easily use C++ code from Matlab without having to modify it. As long as the header is only C, Matlab does not complain if C++ objects are created in the end.
For instance, if the class you want to use from Matlab is:
class MyClass
{
public:
double memberFunction();
};
Have a header file be (add prefix to have functions be exported):
int createObject();
double callFunction( int object );
Have the cpp file be something like:
static std::map<int,MyClass*> mymap;
int createObject()
{
MyClass* obj = new MyClass();
int pos = mymap.size();
mymap[pos] = obj;
return pos;
}
double callFunction( int obj )
{
return mymap[obj]->memberFunction();
}
Now, you can create MyClass objects and access members from Matlab.
You'll need to pass more parameters, handle map content better (check if object exists in the map and return errors if not, delete objects from the map when done...etc), but this is the general idea.
I have a project using cocos2d-x library that contains a lot of classes. I have a .h file contains a global vector. I want to initialize it when the program starts in an intro page class. Intro page class has a graphical surface and a loader. Then I want to use that vector in my main class. The global vector's code is like bellow:
//globals.h
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include <vector>
vector<int> a;
#endif
I am using push_back in intro page class. I have used extern and static keywords. my program makes a runtime linker error and it say your vector have been declared in appDelegate class (base class of cocos2d). when I put a static keyword behind it, it don't give me that linker error but it don't work correctly.
how can I correct this error? if you have another idea instead of this one, please share it. thank you.
You should have a design like the following:
shared.cpp
vector<int> a;
shared.h
extern vector<int> a;
somewhere.cpp
#include "shared.h"
void code() {
a.push_back(10);
}
Mind that, since you are using C++, you can uses classes as namespaces to avoid cluttering the global namespace, eg:
shared.cpp
vector<int> Common::a;
shared.h
class Common {
public:
static vector<int> a;
}
somewhere.cpp
#include "shared.h"
void code() {
Common::a.push_back(10);
}
You may have multiple declarations of an object, but you should only have one definition. To accomplish this, use extern to mark the declarations and the lack of extern to mark the definition.
In your header file, do this:
extern std::vector<int> a;
In exactly one of your source code files, do this:
std::vector<int> a;
I omitted #include "stdafx.h in each file.
stdafx.h (precompiled headers)
#include a.h
#include b.h
class stuff;
stuff * s
a.h
class thing{float f; void fun()};
a.cc
void thing::fun(){}
thing::thing():
f(b->f) {} // lnk 2005 linking error
b.h
struct stuff
{
float f;
thing * t;
};
b.cc
stuff::stuff(): f(3.4) { t = new thing; }
main.cc
int main()
{
s = new stuff;
s -> fun();
}
As you can see, I try to access s which is predeclared in stdafx.h
I'm doing this design so I don't have to rely on singletons (I have one main class which I want to access in other smaller objects)
Do i need to use the extern keyword in some way ? Is the precompiled header causing problem ?
In stdafx.h, you've declared s, but you've never defined it. I would:
Add extern to the declaration in stdafx.h
Add a definition of s in main.cc like this:
stuff * s = NULL;
I suggest removing the global variables. They are dangerous because any task can read and write to it. In mult-thread and multi-task systems, controlling access to the global variable becomes necessary and more complicated.
In my current project, I have demanded that there be no global variables. There can be static local variables with getters and setters. Using getters and setters allows one to slide in patterns to prevent multitasking issues from arising.
Try your best to get rid of a global variable. You've already found one issue against them.
solved it by redesigning code. C++ is not very much clean to use.
Say I have these two classes:
// a.h
#include "b.h"
and:
// b.h
include "a.h"
I understand there is a problem over here, but how can I fix it and use a objects and their methods in b class and vice versa?
You can use forward declarations, like this:
class B;
class A
{
B* ThisIsValid;
}
class B
{
A SoIsThis;
}
For more information, see this SO question.
As for the preprocessor #includes, there's likely a better way to organize your code. Without the full story, though, it's hard to say.
To extend on #Borealid 's answer:
To avoid problems with circular includes, using an "include guard"
eg.
#ifndef MYFILE_H /* If this is not defined yet, it must be the first time
we include this file */
#define MYFILE_H // Mark this file as already included
// This only works if the symbol we are defining is unique.
// code goes here
#endif
You can use what is called a "forward declaration".
For a function, this would be something like void myFunction(int);. For a variable, it might look like extern int myVariable;. For a class, class MyClass;. These bodiless statements can be included before the actual code-bearing declarations, and provide the compiler with enough information to produce code making use of the declared types.
To avoid problems with circular includes, using an "include guard" - an #ifdef at the top of each header file which prevents it being included twice.
The "other" class can only have a reference or pointer to the "first" class.
in file a.h:
#include "b.h"
struct a {
b m_b;
};
in file b.h:
struct a;
struct b {
a* m_a;
};
void using_the_a_instance(b& theb);
in file b.cpp:
#include "b.h"
#include "a.h"
void using_the_a_instance(b& theb)
{
theb.m_a = new a();
}
I have a static library of functions written in C. Let's say the header file is called myHeader.h and looks like:
#ifndef MYHEADER_H
#define MYHEADER_H
void function1();
void function2();
#endif
function1 and function2 aren't anything too special. Let's say they exist in a file called impl1.c which looks like:
#include "myHeader.h"
void function1() {
// code
}
void function2() {
// more code
}
All of the code mentioned so far is compiled into some static library called libMyLib.a. I'd rather not modify any of the code used to build this library. I also have a C++ header (cppHeader.h) that looks like:
#ifndef CPPHEADER_H
#define CPPHEADER_H
class CppClass {
private:
double attr1;
public:
void function3();
};
#endif
Then cppHeader.cpp looks like:
#include "cppHeader.h"
#include "myHeader.h"
// constructor
CppClass::CppClass(){}
void CppClass::function3() {
function1();
}
When I try to compile this, I get an error about an undefined reference to function1(). I believe that I've linked everything properly when compiling. I'm pretty rusty in my C++. I'm sure that I'm just doing something stupid. I hope that my simple example code illustrates the problem well enough.
Thanks in advance for any help!
The other solution (to the one suggested originally by Yann) is to surround your "C" header with:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
Which saves you from having to remember to do:
extern "C" {
#include "foo.h"
}
every place you use foo.h
Make sure to use:
extern "C" {
#include "myHeader.h"
}
Or else the C++ compiler will generate symbol names which are name-mangled.