Abstract database implementation in C++ - c++

I wanna create abstract Db class and implement Pg (postgresql) by inheriting from Db:
Db.h:
template <class T>
class Db
{
public:
Db(std::string, std::string, std::string, std::string);
virtual ~Db();
protected:
T* getConnection();
std::string getHost();
std::string getUsername();
std::string getDatabase();
std::string getPassword();
virtual std::string getConnectionString()=0;
private:
T* connection;
std::string host;
std::string username;
std::string database;
std::string password;
};
Db.cpp:
#include "Db.h"
using namespace std;
template <class T>
Db<T>::Db(string iHost, string iUsername, string iDatabase, string iPassword)
: host(iHost), username(iUsername), database(iDatabase), password(iPassword) {
T* conn(getConnectionString());
connection = conn;
}
template <class T>
T* Db<T>::getConnection() {
return connection;
}
... getters
Pg.h:
#include "../Db.h"
template <class T>
class Pg : public Db<T> {
public:
virtual std::string getConnectionString();
};
Pg.cpp:
#include "Pg.h"
template <class T>
std::string Pg<T>::getConnectionString() {
return "host=" + this->getHost() + " user=" + this->getUsername()
+ " password=" + this->getPassword() + " dbname=" + this->getDatabase();
}
main.cpp:
#include <iostream>
#include <pqxx/connection>
#include <pqxx/transaction>
#include "lib/db/pg/Pg.h"
using namespace std;
int main () {
string host = "localhost";
string username = "username";
string database = "db";
string password = "root";
try {
Pg<pqxx::connection> *db(host, username, database, password);
} catch (pqxx::broken_connection) {
cout << "Failed to establish connection." << endl;
}
return 0;
}
Sorry for long implementation. After compiling with g++ I get an error:
main.cpp: In function ‘int main()’:
main.cpp:15:62: error: expression list treated as compound expression in initializer [-fpermissive]
Pg<pqxx::connection> *db(host, username, database, password);
^
main.cpp:15:62: error: cannot convert ‘std::string {aka std::basic_string<char>}’ to ‘Pg<pqxx::basic_connection<pqxx::connect_direct> >*’ in initialization
I don't know if it is a good idea in the end, because my first version with only main() function looked more compact. I just try to hide connection details somewhere, such as connection string.

In main(), your db variable is declared as a pointer. You cannot pass constructor parameters to a pointer like you are doing.
You need to either:
drop the * from the declaration:
Pg<pqxx::connection> db(host, username, database, password);
keep the * and use new to construct the object:
Pg<pqxx::connection> *db = new Pg<pqxx::connection>(host, username, database, password);
...
delete db;

Related

bind class member funtion to std::function not need check parameters?

why gcc 9.4 not check parameters when bind a class member funtion to a std::function viriable, but check when bind a global function? here is example code, CreateRpcFun has a parameter, but Test member function print doesn't have any other parameters except this, bind print to CreateRpcFun works well, but global funtion print2 cannot, can anybody explain why?
#include <functional>
#include <iostream>
#include <string>
using namespace std;
using CreateRpcFun = std::function<void(const string &)>;
class Test {
public:
Test() : str_("nihao!") {}
// bind print to CreateRpcFun passed compile
void print() { cout << str_ << endl; }
private:
string str_;
};
class Holder {
public:
CreateRpcFun CreateRpc;
};
class Other {
public:
Other(Holder h, string str) : h_(h), str_(str) {}
void run() { h_.CreateRpc("world!"); }
private:
Holder h_;
string str_;
};
void print1(const string &str) { cout << str << endl; }
void print2() { cout << "magic" << endl; }
int main() {
Test t;
Holder h;
h.CreateRpc = std::bind(&Test::print, &t);
Other o(h, "hhhh");
o.run();
h.CreateRpc = &print1;
h.CreateRpc("test");
// h.CreateRpc = &print2; // compile error
// h.CreateRpc("test");
}

Can't seem to push_back abstract objects into vector? [duplicate]

This question already has answers here:
Why can I not push_back a unique_ptr into a vector?
(2 answers)
Closed 3 years ago.
I am trying to create one vector for two types of users. Admin and Customer who are both derived from an abstract class, BaseUser. However I tried some of the answers provided online but I can't seem to make this work. I keep getting error: use of delete function 'std::unique_ptr<....
I am still struggling with fully grasping the concept of pointers so that could be why im stuck with this problem.
#ifndef BASEUSER_H
#define BASEUSER_H
#include <string>
class BaseUser
{
private:
int id;
int idCounter = 0;
std::string fullname;
std::string username;
std::string password;
protected:
bool isAdmin;
public:
BaseUser();
BaseUser(std::string fullname, std::string username, std::string password);
virtual void setIsAdmin(bool isAdmin) = 0;
void setID(int id);
void setFullname(std::string fullname);
void setUsername(std::string username);
void setPassword(std::string password);
unsigned long int getID();
std::string getFullname();
std::string getUsername();
std::string getPassword();
};
#endif
#ifndef ADMIN_H
#define ADMIN_H
#include "BaseUser.h"
class Admin : public BaseUser
{
public:
Admin(std::string fullname,std::string username,std::string password);
void setIsAdmin(bool isAdmin);
bool getIsAdmin();
};
#endif
#ifndef USERMANAGER_H
#define USERMANAGER_H
#include "Admin.h"
#include "Customer.h"
#include <vector>
#include <memory>
class UserManager
{
private:
std::vector<std::unique_ptr<BaseUser>> users;
bool isAuthenticated;
public:
std::vector<std::unique_ptr<BaseUser>> getUsers();
bool login(std::string name, std::string password);
bool logout();
void createAdmin(Admin);
// void createCustomer(Customer);
};
#endif
Object creation method declaration inside the usermanager class:
void UserManager::createAdmin(Admin admin))
{
users.push_back( move(admin) )
}
I also tried to push using make_unique, but still the same error.
View that return the object to the createAdmin() method:
// View.cpp
Admin View::createAdminView()
{
string fullname, username, password;
cout << "~ Register Admin ~" << endl << endl;
cout << "Name: ";
cin.ignore();
getline(cin, fullname);
cout << "Username: ";
cin >> username;
cout << "Password: ";
cin >> password;
return Admin(fullname, username, password);
}
try changing createAdmin into this:
void UserManager::createAdmin(Admin admin)
{
users.push_back( std::make_unique<Admin>(admin) );
}
push_back of a vector<T> wants a const T& or (in this case) a T&&

Request for member, non class-type

i'm getting huge amount of errors in my code, and it all boils down to the following:
Library.cpp:89: error: request for member ‘getLocation’ in ‘((Library*)this)->Library::holdings.std::vector<_Tp, _Alloc>::operator[] [with _Tp = Book*, _Alloc = std::allocator](((long unsigned int)bookOnFile))’, which is of non-class type ‘Book*’
i'm just so confused as to how I should write the following:
Patron* matchPatron = &members[patronOnFile];
if (PatronIDMatch == true && bookIDMatch == true) {
if (holdings[bookOnFile].getLocation() == ON_SHELF) {
holdings[bookOnFile].setCheckedOutBy(matchPatron);
holdings[bookOnFile].setLocation(CHECKED_OUT);
holdings[bookOnFile].setDateCheckedOut(currentDate);
members[patronOnFile].setCheckedOutBooks(&holdings[bookOnFile]);
cout << members[patronOnFile].getName() << " check out successful"
<< holdings[bookOnFile].getTitle() << ".";
(i have the error code for so many lines, this one is just for the getLocation line.)
and my header is the following:
//Library.hpp
#ifndef LIBRARY_HPP
#define LIBRARY_HPP
#include <string>
#include <vector>
#include "Patron.hpp"
class Library {
private:
std::vector<Book*> holdings;
std::vector<Patron*> members;
int currentDate;
public:
Library();
void addBook(Book*);
void addPatron(Patron*);
std::string checkOutBook(std::string pID, std::string bID);
std::string returnBook(std::string bID);
std::string requestBook(std::string pID, std::string bID);
std::string payFine(std::string pID, double payment);
void incrementCurrentDate();
Patron* getPatron(std::string pID);
Book* getBook(std::string bID);
};
#endif
am i just writing my code wrong here? how should I be writing it? i can provide my entire program if needed.
EDIT:
Patron* matchPatron = &members[patronOnFile];
You have a vector of Book*, which are pointers, but you are using dot notation when you call holdings[bookOnFile].getLocation(). Same goes for the other method calls. Try replacing with holdings[bookOnFile]->getLocation(), etc.

Request for Member in ' ' whitch is a non-class type

I want to create a object array of Accounts so I can manage them load everything from a file (by struct).
Im pretty new leaning c++ but I have no idea what I am doing wrong.
What does: Account** accounts[50] ?
"" accounts[i] = new Account*;
"" accounts[i]->newAccount(i, id_string, pw_string, level_int);
ERROR MESSAGE: request for member 'newAccount' in '* accounts[i]', which is of non-class type 'Account*'
AccountManagerFrm.cpp // Mainfile to run everything
#include "AccountManagerFrm.h"
#include "Account.h"
#include "ladeAccounts.h"
using namespace std;
Account** accounts [50];
void AccountManagerFrm::createAccountClick(wxCommandEvent& event)
{
accounts[i] = new Account*;
accounts[i]->newAccount(i, id_string, pw_string, level_int); // ERROR LINE
}
Account.cpp
class Account
{
struct iAccount
{
string ID;
string password;
int level;
};
Account()
{
}
void newAccount(int anzahl, string username, string pw, int lvl)
{
iAccount neu;
neu.ID = username;
neu.password = pw;
neu.level = lvl;
}
};
Account.h
#include <string>
using namespace std;
class Account{
public:
Account();
void newAccount(int anzahl, string username, string pw, int lvl);
void getInformationFromFile();
};
I want to create a object array of Accounts
That's just
Account accounts[50];
not your weird array of pointers to pointers. Then you can access one with .
accounts[i].newAccount(i, id_string, pw_string, level_int);
You'll also need to fix up the class definition. The definition itself, in the header, needs to contain all members. Also, the header should have a guard, to avoid errors if you include the header more than once. It's a bad idea to dump namespace std; into the global namespace; this pollutes the global namespace for everyone who includes the header. The whole header should be something like
#ifndef ACCOUNT_H
#define ACCOUNT_H
#include <string>
class Account {
public:
Account();
void newAccount(int anzahl, std::string username, string std::pw, int lvl);
void getInformationFromFile();
private:
std::string ID;
std::string password;
int level;
};
#endif
The source file should just define the member functions, not redefine the whole class:
#include "Account.h"
Account::Account() {}
void Account::newAccount(int anzahl, std::string username, std::string pw, int lvl)
{
ID = username;
password = pw;
level = lvl;
}
If you're struggling with basic class definitions, then you really should read a good introductory book. This is a complicated language, and you'll never learn it by guessing the syntax.

How to get a whole row from database using SOCI into user-defined object type?

I extended my class (from this question: How to get a whole row from database using SOCI?) to have two private members, also added getters and setters. But when compiling my program, I have errors again.
myClass.h
#include <soci.h>
#include <postgresql/soci-postgresql.h>
#include <string>
class MyClass
{
public:
MyClass();
MyClass(int i, std::string);
void setI(int i);
int getI() const;
void setS(std::string s);
std::string getS() const;
private:
int i_;
std::string s_;
};
namespace soci
{
template <>
struct type_conversion<MyClass>
{
typedef MyClass base_type;
static void from_base(int i, std::string s, soci::indicator ind, MyClass & mi)
{
if (ind == soci::i_null)
{
throw soci_error("Null value not allowed for this type");
}
mi.setI(i);
mi.setS(s);
}
static void to_base(const MyClass & mi, int & i, std::string &s, soci::indicator & ind)
{
i = mi.getI();
s = mi.getS();
ind = soci::i_ok;
}
};
}
myClass.cpp
#include "myClass.h"
MyClass::MyClass()
{
}
MyClass::MyClass(int i, std:string s)
{
this->i_ = i;
this->s_ = s;
}
int MyClass::getI() const
{
return this->i_;
}
void MyClass::setI(int i)
{
this->i_ = i;
}
std::string MyClass::getS() const
{
return this->s_;
}
void MyClass::setS(std::string s)
{
this->s_ = s;
}
myClassTest.cpp
#include <iostream>
#include "myClass.h"
int main(int argc, char **argv)
{
soci::session sql;
sql.open(soci::postgresql, "dbname=mydb user=postgres password=postgrespass");
MyClass i;
sql << "SELECT id, name FROM person;", soci::into(i);
std::cout << i.getI() << " " << i.getS();
sql.close();
return 0;
}
I compile it like this:
g++ myClassTest.cpp myClass.h myClass.cpp -o App -lsoci_core
-lsoci_postgresql -ldl -lpq -I /usr/local/include/soci -I /usr/include/postgresql
And the errors I got are:
In file included from /usr/local/include/soci/into-type.h:13:0,
from /usr/local/include/soci/blob-exchange.h:12,
from /usr/local/include/soci/soci.h:18,
from myClass.h:1,
from myClassTest.cpp:2:
/usr/local/include/soci/exchange-traits.h: In instantiation of ‘soci::details::exchange_traits<MyClass>’:
/usr/local/include/soci/into.h:29:60: instantiated from ‘soci::details::into_type_ptr soci::into(T&) [with T = MyClass, soci::details::into_type_ptr = soci::details::type_ptr<soci::details::into_type_base>]’
myClassTest.cpp:27:65: instantiated from here
/usr/local/include/soci/exchange-traits.h:35:5: error: incomplete type ‘soci::details::exchange_traits<MyClass>’ used in nested name specifier
In file included from /usr/local/include/soci/into.h:13:0,
from /usr/local/include/soci/soci.h:22,
from myClass.h:1,
from myClassTest.cpp:2:
/usr/local/include/soci/type-conversion.h: In member function ‘void soci::details::conversion_into_type<T>::convert_from_base() [with T = MyClass]’:
myClassTest.cpp:34:1: instantiated from here
/usr/local/include/soci/type-conversion.h:59:9: error: no matching function for call to ‘soci::type_conversion<MyClass>::from_base(soci::type_conversion<MyClass>::base_type&, soci::indicator&, MyClass&)’
/usr/local/include/soci/type-conversion.h:59:9: note: candidate is:
myClass.h:28:21: note: static void soci::type_conversion<MyClass>::from_base(int, std::string, soci::indicator, MyClass&)
myClass.h:28:21: note: candidate expects 4 arguments, 3 provided
myClass.cpp:8:28: error: found ‘:’ in nested-name-specifier, expected ‘::’
Have you tried SOCI 3.2? I did something similar with this version which worked pretty well:
vector<Entry> Entry::findByName(string name) {
Entry entry;
vector<Entry> entries;
//Starting a connection to database
session sql(firebird, "service=/srv/firebird/registry.gdb user=SYSDBA password=password");
//Querying data using a prepared statement and place data into a Entry object
statement st = (sql.prepare <<
"select NAME, ADDRESS, PHONE from ENTRY WHERE NAME like '%' || :NAME || '%'",
into(entry), use(name));
st.execute();
//Checking if we can fetch a row from resultset
while (st.fetch())
{
//Pushing the object with mapped data into the entries vector
entries.push_back(entry);
}
return entries;
}
You can change this to:
Entry Entry::findByName(string name) {
Entry entry;
//Starting a connection to database
session sql(firebird, "service=/srv/firebird/registry.gdb user=SYSDBA password=password");
//Querying data using a prepared statement and place data into a Entry object
statement st = (sql.prepare <<
"select NAME, ADDRESS, PHONE from ENTRY WHERE NAME like '%' || :NAME || '%'",
into(entry), use(name));
st.execute();
//Checking if we can fetch a row from resultset
if (st.fetch())
{
return entry;
}
return NULL;
}
Note: Both of them are static classes of my model class which implements a custom version of ActiveRecord.