I am kind of new to C++. I am having trouble setting up my headers. This is
from functions.h
extern void apply_surface(int, int, SDL_Surface *, SDL_Surface *,SDL_Rect *);
And this is the function definition from functions.cpp
void
apply_surface(int x, int y, SDL_Surface * source, SDL_Surface *
destination,SDL_Rect *clip = NULL)
{
...
}
And this is how I use it in main.cpp
#include "functions.h"
int
main (int argc, char * argv[])
{
apply_surface(bla,bla,bla,bla); // 4 arguments, since last one is optional.
}
But, this doesn't compile, because, main.cpp doesn't know last parameter is optional. How can I make this work?
You make the declaration (i.e. in the header file - functions.h) contain the optional parameter, not the definition (functions.cpp).
//functions.h
extern void apply_surface(int, int, SDL_Surface *, SDL_Surface *,SDL_Rect * clip = NULL);
//functions.cpp
void apply_surface(int x, int y, SDL_Surface * source, SDL_Surface *
destination,SDL_Rect *clip /*= NULL*/)
{
...
}
The default parameter value should be in the function declaration (functions.h), rather than in the function definition (function.cpp).
Use:
extern void apply_surface(int, int, SDL_Surface *, SDL_Surface *,SDL_Rect * = NULL);
(note I can't check it here; don't have a compiler nearby).
Strangely enough, it works fine for me if I have a virtual function without a default parameter, and then inheritors in .h files without default parameters, and then in their .cpp files I have the default parameters. Like this:
// in .h
class Base {virtual void func(int param){}};
class Inheritor : public Base {void func(int param);};
// in .cpp
void Inheritor::func(int param = 0){}
Pardon the shoddy formatting
Related
I'm new to ffi. But I successfully used dart-ffi with functions call.
Now, I'd like to use a C++ object in dart ffi. I don't know if it is possible, but I tried like this.
The prototypes of constructor call are :
function_dart = lib
.lookup<NativeFunction<function_native>>("constructor_function")
.asFunction();
But I've got :
Failed to lookup symbol <constructor_function>, where I tried constructor function with :
constructor_function
class::constructor_function
class::constructor_function(args)
I did nm -gDC <lib>, and I can see the constructor.
Help !
edit 1 : #Botje, #Richard-Heap
I'm trying to use the VideoCapture instance from OpenCV.
I have followed the instructions from Botje's answer.
So I created a lib, like this :
bind.hpp :
#ifndef BIND_HPP
# define BIND_HPP
#include <opencv2/videoio.hpp>
extern "C" {
cv::VideoCapture *cvCreateVideoCapture(char *filename, int apiPreference);
}
#endif
bind.cpp :
#include "bind.hpp"
cv::VideoCapture *createVideoCapture(char *filename, int apiPreference) {
return new cv::VideoCapture(filename, apiPreference);
}
The commands I use to compile :
g++ -c bind.cpp -lopencv -o bind.o
g++ bind.o -shared -o bind.so
I get : dart: symbol lookup error: ./lib/src/bind.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi
Next step, is to use a method of VideoCapture instance.
Thank you
Dart ffi uses a C interface, so you have to adapt as follows.
Start with C++ class
Rect::Rect(int32_t width, int32_t height) {
m_width = width;
m_height = height;
}
void Rect::setWidth(int32_t width) {
m_width = width;
}
void Rect::setHeight(int32_t height) {
m_height = height;
}
int32_t Rect::area() {
return m_width * m_height;
}
create a C adapter header
EXTERNC void* rect_init(int32_t width, int32_t height);
EXTERNC void rect_destroy(void *ptr);
EXTERNC int32_t rect_area(void *ptr);
and implementation
void* rect_init(int32_t width, int32_t height){
return new Rect(width, height);
}
void rect_destroy(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
delete typed_ptr;
}
int32_t rect_area(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
return typed_ptr->area();
}
in Dart, create the typedefs
typedef example_init_rect = Pointer<Void> Function(Int32 w, Int32 h);
typedef ExampleInitRect = Pointer<Void> Function(int w, int h);
typedef example_free_rect = Void Function(Pointer<Void> p);
typedef ExampleFreeRect = void Function(Pointer<Void> p);
typedef example_area_rect = Int32 Function(Pointer<Void> p);
typedef ExampleAreaRect = int Function(Pointer<Void> p);
and bind the C adapter functions. Finally, you could create a Dart class that proxies the underlying C++ class.
class NativeRect {
Pointer<Void> _nativeInstance;
NativeRect(int width, int height) {
_nativeInstance = Example()._exInitRect(width, height);
}
void free() {
Example()._exFreeRect(_nativeInstance);
}
int get area => Example()._exAreaRect(_nativeInstance);
}
C++ compilers use "name mangling" to ensure symbol names are unique. The fact that you had to add the -C option (or --demangle) to make it show up is a hint.
For example, here is the mangled symbol for some_class::some_class(int, std::string):
_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
You will need to pass the mangled name (not the demangled name) in order to call the constructor. You will also need to match the ABI for an object (ie have a pointer to the object's memory in the correct register). Sometimes this is simply a hidden first argument to the constructor, but not in all ABIs.
If at all possible, write a C++ wrapper function that constructs the object for you and tag it with extern "C" so you don't have to jump through these hoops.
For example:
extern "C"
some_class* create_some_class(int x, const char * some_text) {
return new some_class(x, some_text);
}
You can now simply call create_some_class from Dart with basic types and you will get back a pointer to the constructed C++ object.
If you intend to wrap a large API like this, consider migrating to something like SWIG that can auto-generate these wrappers.
I'm new to ffi. But I successfully used dart-ffi with functions call.
Now, I'd like to use a C++ object in dart ffi. I don't know if it is possible, but I tried like this.
The prototypes of constructor call are :
function_dart = lib
.lookup<NativeFunction<function_native>>("constructor_function")
.asFunction();
But I've got :
Failed to lookup symbol <constructor_function>, where I tried constructor function with :
constructor_function
class::constructor_function
class::constructor_function(args)
I did nm -gDC <lib>, and I can see the constructor.
Help !
edit 1 : #Botje, #Richard-Heap
I'm trying to use the VideoCapture instance from OpenCV.
I have followed the instructions from Botje's answer.
So I created a lib, like this :
bind.hpp :
#ifndef BIND_HPP
# define BIND_HPP
#include <opencv2/videoio.hpp>
extern "C" {
cv::VideoCapture *cvCreateVideoCapture(char *filename, int apiPreference);
}
#endif
bind.cpp :
#include "bind.hpp"
cv::VideoCapture *createVideoCapture(char *filename, int apiPreference) {
return new cv::VideoCapture(filename, apiPreference);
}
The commands I use to compile :
g++ -c bind.cpp -lopencv -o bind.o
g++ bind.o -shared -o bind.so
I get : dart: symbol lookup error: ./lib/src/bind.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi
Next step, is to use a method of VideoCapture instance.
Thank you
Dart ffi uses a C interface, so you have to adapt as follows.
Start with C++ class
Rect::Rect(int32_t width, int32_t height) {
m_width = width;
m_height = height;
}
void Rect::setWidth(int32_t width) {
m_width = width;
}
void Rect::setHeight(int32_t height) {
m_height = height;
}
int32_t Rect::area() {
return m_width * m_height;
}
create a C adapter header
EXTERNC void* rect_init(int32_t width, int32_t height);
EXTERNC void rect_destroy(void *ptr);
EXTERNC int32_t rect_area(void *ptr);
and implementation
void* rect_init(int32_t width, int32_t height){
return new Rect(width, height);
}
void rect_destroy(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
delete typed_ptr;
}
int32_t rect_area(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
return typed_ptr->area();
}
in Dart, create the typedefs
typedef example_init_rect = Pointer<Void> Function(Int32 w, Int32 h);
typedef ExampleInitRect = Pointer<Void> Function(int w, int h);
typedef example_free_rect = Void Function(Pointer<Void> p);
typedef ExampleFreeRect = void Function(Pointer<Void> p);
typedef example_area_rect = Int32 Function(Pointer<Void> p);
typedef ExampleAreaRect = int Function(Pointer<Void> p);
and bind the C adapter functions. Finally, you could create a Dart class that proxies the underlying C++ class.
class NativeRect {
Pointer<Void> _nativeInstance;
NativeRect(int width, int height) {
_nativeInstance = Example()._exInitRect(width, height);
}
void free() {
Example()._exFreeRect(_nativeInstance);
}
int get area => Example()._exAreaRect(_nativeInstance);
}
C++ compilers use "name mangling" to ensure symbol names are unique. The fact that you had to add the -C option (or --demangle) to make it show up is a hint.
For example, here is the mangled symbol for some_class::some_class(int, std::string):
_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
You will need to pass the mangled name (not the demangled name) in order to call the constructor. You will also need to match the ABI for an object (ie have a pointer to the object's memory in the correct register). Sometimes this is simply a hidden first argument to the constructor, but not in all ABIs.
If at all possible, write a C++ wrapper function that constructs the object for you and tag it with extern "C" so you don't have to jump through these hoops.
For example:
extern "C"
some_class* create_some_class(int x, const char * some_text) {
return new some_class(x, some_text);
}
You can now simply call create_some_class from Dart with basic types and you will get back a pointer to the constructed C++ object.
If you intend to wrap a large API like this, consider migrating to something like SWIG that can auto-generate these wrappers.
I have two classes, and this is the header of one of them:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
#include <SDL/SDL.h>
using namespace std;
class Wrapper
{
private:
//SDL_Surface *screen;
public:
static SDL_Surface *screen;
static void set_screen(SDL_Surface *_screen);
static void set_pixel(int x, int y, Uint8 color);
static void clear_screen(int r, int g, int b);
static SDL_Surface* load_image(char path[500]);
static void draw_image(SDL_Surface *img, int x, int y, int width, int height);
static void draw_line(int x1, int y1, int x2, int y2, Uint8 color);
};
#endif
I am calling Wrapper::set_screen(screen) from another file and I get this error:
In file included from /home/david/src/aships/src/Wrapper.cpp:6:0:
/home/david/src/aships/src/Wrapper.hpp: In static member function ‘static void Wrapper::set_screen(SDL_Surface*)’:
/home/david/src/aships/src/Wrapper.hpp:11:18: error: invalid use of member ‘Wrapper::screen’ in static member function
/home/david/src/aships/src/Wrapper.cpp:10:3: error: from this location
I also get a similar error for the definition of every single function on Wrapper.cpp, for example:
void Wrapper::set_pixel(int x, int y, Uint8 color)
{
/* Draws a pixel on the screen at (x, y) with color 'color' */
Uint8 *p;
p = (Uint8 *) screen->pixels + y * screen->pitch + x * screen->format->BytesPerPixel;
*p = color;
}
On compile:
/home/david/src/aships/src/Wrapper.hpp: In static member function ‘static void Wrapper::set_pixel(int, int, Uint8)’:
/home/david/src/aships/src/Wrapper.hpp:11:18: error: invalid use of member ‘Wrapper::screen’ in static member function
/home/david/src/aships/src/Wrapper.cpp:17:17: error: from this location
I know it's related to the class being static and thus the variable Wrapper.screen is not accessible or something, but I'm not sure of how to fix it. Any ideas?
You are using a static variable
static SDL_Surface *screen;
in your code.
In C++ when you declare a static variable in the .h (or .hpp) you are creating a variable that is general (static) to the class. Thus, to use it in another file you have to redeclare it (which I'm guessing you didn't) to create a variable in that file referencing the static one. In your case put this:
SDL_Surface* Wrapper::screen;
in the .cpp file.
I'm not sure the theory is well explained, but it works like that.
Your class and member (screen) are not static, which means they don't actually exist.
You can't access a non static member in a static function.
Try to make your data members to be static.
I'm not convinced that the code abstract you show us is an accurate characterization of your problem.
Your header should not include using namespace std; — it doesn't use or declare anything from the std namespace, and specifying using namespace std; is generally regarded as 'not a good idea', doubly so when it appears in a header file.
It also isn't clear that your header needs to include SDL/SDL.h. If the Uint8 type is easily isolated (not necessarily valid), then your header file can simply use a forward declaration of the SDL_Surface class. (Your implementation code will need to include SDL/SDL.h; but you should not burden the users of your wrapper class with unnecessary #include directives when simple forward declarations would suffice.)
This code is self-contained (does not need any headers), but more or less simulates what you could use, and it compiles OK:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
typedef unsigned char Uint8;
class SDL_Surface;
class Wrapper
{
public:
static SDL_Surface *screen;
static void set_screen(SDL_Surface *_screen);
static void set_pixel(int x, int y, Uint8 color);
static void clear_screen(int r, int g, int b);
static SDL_Surface *load_image(char path[500]);
static void draw_image(SDL_Surface *img, int x, int y, int width, int height);
static void draw_line(int x1, int y1, int x2, int y2, Uint8 color);
};
#endif
//#include <SDL/SDL.h>
typedef unsigned short Uint16;
class SDL_Surface
{
public:
Uint8 *pixels;
Uint16 pitch;
struct
{
Uint8 BytesPerPixel;
} *format;
};
// End of SDL/SDL.h
void Wrapper::set_pixel(int x, int y, Uint8 color)
{
/* Draws a pixel on the screen at (x, y) with color 'color' */
Uint8 *p;
p = (Uint8 *) screen->pixels + y * screen->pitch + x * screen->format->BytesPerPixel;
*p = color;
}
It also compiles without warnings. The (Uint8 *) cast (copied from the original) is unnecessary. With the class definition given, it is superfluous; if you are needing to use a cast because the type of the pixels member of SDL_Surface actually isn't Uint8, are you sure it is a good idea? And can't you use reinterpret_cast<Uint8>(screen->pixels) instead to make it clearer?
Can you reduce your problem to code analogous to this that still shows the actual error?
I am kind of new to C++. I am having trouble setting up my headers. This is
from functions.h
extern void apply_surface(int, int, SDL_Surface *, SDL_Surface *,SDL_Rect *);
And this is the function definition from functions.cpp
void
apply_surface(int x, int y, SDL_Surface * source, SDL_Surface *
destination,SDL_Rect *clip = NULL)
{
...
}
And this is how I use it in main.cpp
#include "functions.h"
int
main (int argc, char * argv[])
{
apply_surface(bla,bla,bla,bla); // 4 arguments, since last one is optional.
}
But, this doesn't compile, because, main.cpp doesn't know last parameter is optional. How can I make this work?
You make the declaration (i.e. in the header file - functions.h) contain the optional parameter, not the definition (functions.cpp).
//functions.h
extern void apply_surface(int, int, SDL_Surface *, SDL_Surface *,SDL_Rect * clip = NULL);
//functions.cpp
void apply_surface(int x, int y, SDL_Surface * source, SDL_Surface *
destination,SDL_Rect *clip /*= NULL*/)
{
...
}
The default parameter value should be in the function declaration (functions.h), rather than in the function definition (function.cpp).
Use:
extern void apply_surface(int, int, SDL_Surface *, SDL_Surface *,SDL_Rect * = NULL);
(note I can't check it here; don't have a compiler nearby).
Strangely enough, it works fine for me if I have a virtual function without a default parameter, and then inheritors in .h files without default parameters, and then in their .cpp files I have the default parameters. Like this:
// in .h
class Base {virtual void func(int param){}};
class Inheritor : public Base {void func(int param);};
// in .cpp
void Inheritor::func(int param = 0){}
Pardon the shoddy formatting
I am using Microsoft Visual Studio 2010 and the OpenCV 2.3.0 libraries to write up an application for image processing.
I have a piece of code that is erroneous for me and I am not sure how to fix it. I am implementing an application where there will be 2 or 3 windows open at the same time and I want each one of them to be assigned with a different CvMouseCallback function. I want all these CvMouseCallback functions to be in a different class together with another function that returns a pointer to one of these functions according to what the user selects.
My Window.h contains this piece of code.
class Window
{
public:
... // constructors and destructors
void setMouseHandler( CvMouseCallback mouseHandler );
private:
... // other stuff
};
and Window.cpp
#include "stdafx.h"
void Window::setMouseHandler( CvMouseCallback mouseHandler )
{
cvSetMouseCallback( win, mouseHandler, NULL );
}
Now, the MouseHandler.h file
class MouseHandler
{
public:
...
CvMouseCallback selectHandler( int option );
void __cdecl selectROI( int event, int x, int y, int flags, void *param );
private:
Image *in;
Window *win;
void ( CV_CDECL MouseHandler::*callback )( int event, int x, int y, int flags, void *param );
};
and lastly, in MouseHandler.cpp I contain
void __cdecl MouseHandler::selectROI( int event, int x, int y, int flags, void *param )
{
//do something
}
CvMouseCallback MouseHandler::selectHandler( int option )
{
callback = (MouseHandler::selectROI);
return callback;
}
The last bit of information you might need is the definition of CvMouseCallback from the OpenCV library which is
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
Now, the question is: When I return the callback from the last function in MouseHandler.cpp it is underlined with an error saying:
Error: return value type does not match the function type.
I know what it says is that I am trying to impose to that function to return something that does not look like the object it is being asking for. However, it's just a function and if I could do that in the main class it would be ok. My problem is how can selectHandler return a pointer to the selectROI function so that it can be used by another class?
I think that you need to use a static function here:
static void __cdecl selectROI( int event, int x, int y, int flags, void *param );
and
void ( CV_CDECL *callback )( int event, int x, int y, int flags, void *param );
accordingly.
The thing is that this definition:
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
Is not a class member function, while yours is a member of class MouseHandler, which means its a different signature and different parameter list (to accommodate for this). Using static class member function solves it for you.
You'll have to figure out how to pass the object context data to the static function of course.
Your selectROI() method, since it is not static, requires an implicit this parameter as its first argument. If you try making it static, you will have a better chance at getting it working, though really if you are passing it to a C API as you are, you technically need to pass an extern "C" function pointer for everything to be fully proper and portable. That might be a trivial forwarding function like this:
extern "C" void selectROI( int event, int x, int y, int flags, void *param );
Then, if you want your C++ class method to not be static (so it can access class member variables), you just need to pass a pointer to a MouseHandler object as the third argument to cvSetMouseCallback() and you will then receive the same in your callback, which can then look like this:
extern "C" void selectROI( int event, int x, int y, int flags, void *param )
{
static_cast<MouseHandler*>(param)->selectROI( event, x, y, flags);
}