I’m trying to make the SQLite callback function part of my class. Any examples? I have tried this but it isn't compiling:
class Customer
{
...
public:
int callback(void* data, int argc, char **argv, char **azColName);
};
std::string Customer::getCustomer()
{
...
int res = sqlite3_exec(db, sqlStatement.c_str(), callback, nullptr, &errMessage);
...
}
The problem is with callback parameter in sqlite3_exec.
You should use static method for sqlite3_exec as a callback.
define:
static int callback(void* data, int argc, char **argv, char **azColName);
call:
int res = sqlite3_exec(db, sqlStatement.c_str(), Customer::callback, nullptr, &errMessage);
Related
I'm working on my first C++ project. I have 2 classes: 1 for the interaction with the sqlite db, the other one for the qt main window. In the main I create a new window. In the window constructor I would like to load the content of the db and display it in a QtWidget.
So if I understand well sqlite callback function will be called for each row that the sqlite3_exec returns. I made a select_all function in the database class which takes a callback function as an argument so I'll be able to do use the same sql function to display/use the data in different ways.
#include <cstdio>
#include <iostream>
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <qmainwindow.h>
#include <qstandarditemmodel.h>
#include <sqlite3.h>
#include <string>
using namespace std;
class Database {
public:
sqlite3* db;
Database() {db = create_or_open_database();}
sqlite3* create_or_open_database()
{
sqlite3 *db = NULL;
const char *query;
int ret = 0;
char *errorMsg = 0;
ret = sqlite3_open("expense.db", &db);
query = "CREATE TABLE IF NOT EXISTS EXPENSES(NAME TEXT KEY NOT NULL, AMOUNT INT NOT NULL, TAG TEXT, SUBTAG TEXT, DATE CHAR(10) NOT NULL);";
ret = sqlite3_exec(db, query, callback, 0, &errorMsg);
return db;
}
void select_all(int (*f)(void*, int, char**, char**)){
int ret = 0;
char *errorMsg = 0;
const char *query = "SELECT * FROM EXPENSES";
ret = sqlite3_exec(db, query, (*f), 0, &errorMsg);
}
};
class MainWindow
{
public:
QWidget window;
Database expenses;
QTreeView *navigateView = new QTreeView;
QTreeView *expensesList = new QTreeView;
QPushButton *newButton = new QPushButton;
QVBoxLayout *mainVLayout = new QVBoxLayout;
QHBoxLayout *listHLayout = new QHBoxLayout;
QStandardItemModel *expensesModel = new QStandardItemModel;
MainWindow()
{
QSizePolicy navigateSize(QSizePolicy::Preferred, QSizePolicy::Preferred);
QSizePolicy expenseListSize(QSizePolicy::Preferred, QSizePolicy::Preferred);
navigateSize.setHorizontalStretch(1);
navigateView->setSizePolicy(navigateSize);
expenseListSize.setHorizontalStretch(2);
expensesList->setSizePolicy(expenseListSize);
newButton->setText("New");
listHLayout->addWidget(navigateView);
listHLayout->addWidget(expensesList);
mainVLayout->addLayout(listHLayout);
mainVLayout->addWidget(newButton);
window.setLayout(mainVLayout);
// int (MainWindow::*foo)(void*, int, char**, char**) = &MainWindow::display_expenses_in_list;
// expenses.select_all(foo);
expenses.select_all(this->display_expenses_in_list);
}
int display_expenses_in_list(void *NotUsed, int argc, char **argv, char **azColName)
{
QStringList list = {"Name", "Amount (€)", "Tag", "Subtag", "Date"};
this->expensesModel->setVerticalHeaderLabels(list);
// here I'll create items and add them to the QTreeView
return 0;
}
};
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow ui;
ui.window.show();
return app.exec();
}
With this code I get reference to a non-static member function must be called [bound_member_function]
If googled it and tried, I guess, to create a function pointer foo that point to the callback function (the lines that are currently commented). I get this : Cannot initialize a parameter of type 'int (*)(void *, int, char **, char **)' with an lvalue of type 'int (MainWindow::*)(void *, int, char **, char **)' [init_conversion_failed]
If I make display_expenses_in_list static then I can't edit the expensesModel...
The key here is that void* argument to sqlite3_exec. You now pass 0, but you need to pass this instead.
You can now make display_expenses_in_list static. That NotUsed parameter then becomes used. You just need to cast it back to MainWindow* and use it instead of this.
The problem:
The problem is your display_expenses_in_list(...) function is a class member function. Therefore your need to use a pointer to a member function rather than a pointer to a function, because it must always be called on an instance of the class it's a member of - however the sqlite library will only take a void* function pointer.
Check out this article: https://isocpp.org/wiki/faq/pointers-to-members
The fix:
Modern C++ to the rescue here. Wrap up your whole class member function call up in a lambda with the class instance in scope, then pass a pointer to this new, anonymous function as the callback.
Check this stackoverflow answer out showing how to do it (copied below): https://stackoverflow.com/a/31461997/410072
An example (copied from the linked answer):
if (sqlite3_exec(this->db, this->SQL_SELECT_READINGS_QUERY,
+[](void* instance, int x, char** y, char** z) {
return static_cast<dataSend_task*>(instance)->callback(x, y, z);
},
this,
&err))
{
/* whatever */
}
I have a static method inside my class, which I use for a callback.
Inside this callback I want to add a value to result.
This seems not to be possible because of the recast(?).
Is there a way to access the member variable result and add values to it after recasting, or do I need to think of a different way?
MyClass.h
class MyClass
{
public:
vector<string> result;
static int c_CB(void *data, int argc, char **argv, char **azColName);
int Callback(int argc, char **argv, char **azColName);
void Do(string query);
}
MyClass.cpp
void MyClass:Do(string query)
{
sqlite3_exec(this->dbResource, query.c_str(), this->c_CB , NULL, &this->errorMsg);
}
int MyClass::c_CB(void *NotUsed, int argc, char **argv, char **azColName)
{
MyClass* bar = reinterpret_cast<MyClass*>(NotUsed);
// after reinterpret cast, it does not work
//bar->result.insert(bar->result.end(), "foo");
// function call works
return bar->Callback(argc, argv, azColName);
}
int MyClass::Callback(int argc, char **argv, char **azColName)
{
cout << "working" << endl;
}
main.cpp
int main()
{
MyClass* cl = new MyClass();
cl->Do("something");
}
The documentation states that the fourth argument to sqlite3_exec is passed as the first argument of the callback.
Currently you are passing NULL, which you then cast to a MyClass* and attempt access the object, which results in undefined behaviour.
Use this as the fourth argument in place of NULL.
It seems you are trying to access a non-static member function from a static member callback function c_CB.
You were able to call a member function Callback but nothing from the class is accessible, but if I'm correct, the compiler just interpreted Callback as a static function.
If you actually breakpoint inside this function, you can see that none of your member variables actually have a memory address. And the current class, this is null
I'm not sure if the cout << statement still works or if its causing the problem
This is a possible solution to your issue, although it may not be the best one.
class MyClass
{
public:
vector<string> result;
static int c_CB(void *data, int argc, char **argv, char **azColName);
int Callback(int argc, char **argv, char **azColName);
void Do(string query);
void MemberFunction()
{
cout << "working" << endl;
}
static MyClass* currentClass; //Add a static class pointer and assign your class address to it before firing the callback.
}
MyClass* MyClass::currentClass = NULL;
void MyClass:Do(string query)
{
sqlite3_exec(this->dbResource, query.c_str(), this->c_CB , NULL, &this->errorMsg);
}
int MyClass::c_CB(void *NotUsed, int argc, char **argv, char **azColName)
{
MyClass* bar = reinterpret_cast<MyClass*>(NotUsed);
// after reinterpret cast, it does not work
//bar->result.insert(bar->result.end(), "foo");
// function call works
return bar->Callback(argc, argv, azColName);
}
int MyClass::Callback(int argc, char **argv, char **azColName)
{
currentClass->MemberFunction();
}
int main()
{
MyClass* cl = new MyClass();
MyClass::currentClass = this;
cl->Do("something");
}
I want to read argv[1] as char* so this is what I do
using namespace std;
const char *myarg = NULL;
void Plots(char* file);
int main( int size_t argc, char* argv[] ) {
myarg = argv[1];
cout<<" this is a test "<<argv[1]<<endl;
Plots(argv);
}
void Plots(char* fileList){
cout<< argument passed correctly "<<endl;
}
}
However, when executing I get
Error: Function Plot() is not defined in current scope :0:
argv is a char *[], which for all practical purposes is char **.
You declared
void Plots(char * file);
The parameter to Plots() is a char *.
Plots(argv);
This attempts to pass a char ** to a function that takes char * as a parameter.
Additionally, although you declared
void Plots(char * file);
but then you went ahead and defined
void Plot(char* fileList)
Furthermore:
cout<< argument passed correctly "<<endl;
There's a quote missing here.
So, there's three different bugs here.
Simple question, how can I run a program having main inside a class?
I have a code:
MojSwiat2.cpp:
int Main::main() {
// code
return 0;
}
And MojSwiat2.h:
class Main {
public:
int main();
};
Main run;
int Main::main() { // with this I have error: function int Main::main(void) already has a body
run.main();
} // and without I got unresolved external symbol _main referenced in function __tmainCRTStartup
Reason I need to do this: Accessing protected members of class from main
By defining a normal main that only contains a call to your other function. Like this:
int main(int, char**) {
return Main().main();
}
int main(int argc, char* argv[])
{
Main m;
return m.main();
}
or if Main::main is declared static
int main(int argc, char* argv[])
{
return Main::main();
}
You still need to define main.
class my_app {
int main(int argc, char* argv[])
{
// ...
}
}
my_app app;
int main(int argc, char *argv[])
{
return app.main(argc, argv);
}
I'm building an ANE. In one of my calls into native code, there's an object that gets created, and I'd like to be able to keep that in memory to reference in a future call.
I thought I could could do this by creating a pointer to the object, and then passing that pointer to FRESetContextNativeData() as in the example below:
FREObject storeData(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
char* data = "testing...";
FRESetContextNativeData( ctx, &data );
return getFREString(data);
}
FREObject retrieveData(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
char* data;
FREGetContextNativeData(ctx, (void**)&data);
return getFREString(data);
}
This doesn't seem to work however. At the end of retrieveData(), data points to a bunch of randomness. What gives?
So I'm a bit of an idiot. The mistake I made was putting & before data in my call to FRESetContextNativeData(). That one just needs a pointer, not a pointer to a pointer like FREGetContextNativeData().
The following code produces the results I was expecting:
FREObject storeData(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
char* data = "testing..."
FRESetContextNativeData( ctx, (void*)data );
return getFREString(data);
}
FREObject retrieveData(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
char *data;
FREGetContextNativeData(ctx, (void**)&data);
return getFREString(data);
}