Calling a member function of class using objects giving lookup error - c++

I am trying to build plugins in c++ using boost library. helper.h
Header file:
#include <string>
#ifndef HELPER_H
#define HELPER_H
class Helper
{
public:
std::string s;
void helper_new(std::string a);
};
#endif
I defined the member function in a file helper.cpp
#include "helper.h"
namespace boostfs = boost::filesystem;
namespace boostdll = boost::dll;
namespace dll = boost::dll;
// Member Functions()
void Helper::helper_new(std::string a)
{
//int i=0;
std::cout<<"Inside helper_new function!!";
std::cout<<"\n";
std::cout<<a;
std::cout<<"\n";
/*std::ofstream MyFile("/home/deepansh/Desktop/Plugin_example/outputs/helper.txt");
std::cout << "Writing in helper.txt\n"; */
/*for(i=0;i<LONG_MAX;i++)
for(int j=0;j<LONG_MAX;j++);*/
/*MyFile<<a+" ";
MyFile<<i;
MyFile<<"\n";
MyFile.close();*/
std::cout << "Done\n";
}
int main() {
Helper obj;
std::string a;
std::cout<<"Enter string u want to write?";
std::getline(std::cin, a);
obj.s=a;
int choice=1;
std::cout<<"which strat to use? \'1\' or \'2\' ?(default is 1)";
std::cin>>choice;
std::string file="strat"+std::to_string(choice);
boostfs::path lib_path = boostfs::current_path();
boost::filesystem::path p2(std::string(lib_path.string()).append("/plugins/").append(file).append(".so"));
boost::shared_ptr<plugin_api> plugin; // variable to hold a pointer to plugin variable
std::cout << "Loading the plugin" << std::endl;
plugin = dll::import<plugin_api>( // type of imported symbol is located between `<` and `>`
p2, // path to the library and library name
"plugin", // name of the symbol to import
dll::load_mode::append_decorations // makes `libmy_plugin_sum.so` or `my_plugin_sum.dll` from `my_plugin_sum`
);
plugin->handle_task(obj);
std::cout << plugin->print() << std::endl;
}
I called the member function from another file with the help of object of Helper class passed to it as argument(this is compiles as so file) strat1.cpp
#include "../helper.h"
#include <string>
namespace my_namespace {
class strat : public plugin_api {
public:
strat() {
std::cout << "Constructing start" << std::endl;
}
std::string print() const {
return "Hello from strat 1";
}
int handle_task(Helper a) {
//long i=0;
//std::ofstream fout;
//fout.open("/home/deepansh/Desktop/Plugin_example/outputs/strat1.txt");
std::cout<<"Inside strat 1";
std::cout<<"\n";
/*for(i=0;i<LONG_MAX;i++)
for(int j=0;j<LONG_MAX;j++);*/
//fout<<a.s+" ";
//fout<<i;
//fout<<"\n";
//fout.close();
std::cout<<a.s;
std::cout<<"\n";
std::cout<<"going to the helper class function.";
std::string p="Hello man. What's up?";
a.helper_new(p); //error is here
return 0;
}
~strat() {
std::cout << "Destructing strat ;o)" << std::endl;
}
};
I am getting this error ./a.out: symbol lookup error: /home/deepansh/Desktop/Plugin_example/plugins/strat1.so: undefined symbol: _ZN6Helper10helper_newENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
When compiling the code can someone help. compiling:
Convert the plugin library(plugin implementation) to object file by using:
gcc -c -Wall -Werror -fpic strat1.c ../helper.cpp //here -wall and -Werror are for warnings
Then convert the .o files to .so files using(creating shared library from object file) :
gcc -shared -o strat1.so strat1.o
g++-8 helper.cpp -L/usr/lib/x86_64-linux-gnu -lboost_filesystem -L/usr/lib/x86_64-linux-gnu -lboost_system -ldl
when I run the executable a.out the error occurs

Related

Best Way to Deal With Headers and Source Files

I always arranged my C++ headers and source files this way:
prog.h
#include <iostream>
class Prog
{
public:
Prog(std::string);
~Prog();
void printName();
private:
std::string name;
};
#include "prog.cpp"
prog.cpp
Prog::Prog(std::string n):
name(n)
{
std::cout << "Program \"" << name << "\" started.\n";
}
Prog::~Prog()
{
std::cout << "Program \"" << name << "\" ended.\n";
}
void Prog::printName()
{
std::cout << "Program name is: \"" << name << "\".\n";
}
main.cpp
#include "prog.h"
int main()
{
Prog prog {"MyCalculator"};
prog.printName();
return 0;
}
But I recently discovered that it's common to arrange them this other way:
prog.h
class Prog
{
public:
Prog(std::string);
~Prog();
void printName();
private:
std::string name;
};
prog.cpp
#include <iostream>
#include "prog.h"
Prog::Prog(std::string n):
name(n)
{
std::cout << "Program \"" << name << "\" started.\n";
}
Prog::~Prog()
{
std::cout << "Program \"" << name << "\" ended.\n";
}
void Prog::printName()
{
std::cout << "Program name is: \"" << name << "\".\n";
}
main.cpp
#include <iostream>
#include "prog.h"
int main()
{
Prog prog {"MyCalculator"};
prog.printName();
return 0;
}
I find the first method more convenient, so is there any reason why I should prefer the second method over the first one?
Header files shouldn't include source code.
I think the first method could provoke dependency errors in a complex enough project (for example, using circular dependencies), because don't separate declaration and definition.
The compilation time is faster in the second one, because you can compile each source file separately.
Also, you might find this question useful.
The first version is what the book "Accelerated C++" (ed. 2000) suggests to do when first introducing header files for class declarations.
I suppose the second version can be seen as more elegant because it groups together all #include pre-compiler statements at the beginning of the program.

clang: error: linker command failed with exit code 1 (use -v to see invocation) console app

this code should work but I am getting a linker error. I don't know where to look to fix this. I keep seeing things about cocoa pods and I don't have cocoa pods.
//main.cpp
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "ItemToPurchase.cpp"
#include "ItemToPurchase.hpp"
int main(int argc, const char * argv[]) {
// insert code here...
// create objects
ItemToPurchase item1;
//ItemToPurchase item2;
std::cout << "Item1" << std::endl;
item1.setName();
//item1.SetPrice();
//item1.SetQuantity();
std::cout << "Item2" << std::endl;
//item2.setName();
//item2.SetPrice();
//item2.SetQuantity();
//test
std::cout << std::endl << std::endl;
//item1.getName();
//item1.GetPrice();
//item1.GetQuantity();
return 0;
}
here is the ItemToPurchase class cpp file
//ItemToPurchase
#include "ItemToPurchase.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
std::string ItemToPurchase::setName(){
std::cout << "Enter the item name: " << std::endl;
std::cin >> ItemToPurchase::ItemName;
return ItemToPurchase::ItemName;
}
/*
std::string ItemToPurchase::getName() {
return ItemToPurchase::ItemName;
}
int ItemToPurchase::SetPrice(){
std::cout << "Enter the item price: " << std::endl;
std::cin >> ItemToPurchase::ItemPrice;
return ItemToPurchase::ItemPrice;
}
int ItemToPurchase::GetPrice(){
return ItemToPurchase::ItemPrice;
}
int ItemToPurchase::SetQuantity() {
std::cout << "Enter the Quantity: " << std::endl;
std::cin >> ItemToPurchase::ItemQuantity;
return 0;
}
int ItemToPurchase::GetQuantity() {
return ItemToPurchase::ItemQuantity;
}
*/
and here is the header file for that cpp file it just has the class declaration.
#ifndef ItemToPurchase_hpp
#define ItemToPurchase_hpp
#include <stdio.h>
#include <stdlib.h>
#include <string>
class ItemToPurchase {
public:
std::string setName();
std::string getName();
int SetPrice();
//int GetPrice();
//int GetQuantity();
//int SetQuantity();
//ItemToPurchase();
private:
std::string ItemName = "none";
int ItemPrice = 0;
int ItemQuantity = 0;
} items;
#endif /* ItemToPurchase_hpp */
and this is the full error
duplicate symbol __ZN14ItemToPurchase7setNameEv in:
/Users/devintripp/Library/Developer/Xcode/DerivedData/zybooksLab4-alhksylvtcikaegvkzyxidlzoyib/Build/Intermediates.noindex/zybooksLab4.build/Debug/zybooksLab4.build/Objects-normal/x86_64/ItemToPurchase.o
/Users/devintripp/Library/Developer/Xcode/DerivedData/zybooksLab4-alhksylvtcikaegvkzyxidlzoyib/Build/Intermediates.noindex/zybooksLab4.build/Debug/zybooksLab4.build/Objects-normal/x86_64/main.o
duplicate symbol _items in:
/Users/devintripp/Library/Developer/Xcode/DerivedData/zybooksLab4-alhksylvtcikaegvkzyxidlzoyib/Build/Intermediates.noindex/zybooksLab4.build/Debug/zybooksLab4.build/Objects-normal/x86_64/ItemToPurchase.o
/Users/devintripp/Library/Developer/Xcode/DerivedData/zybooksLab4-alhksylvtcikaegvkzyxidlzoyib/Build/Intermediates.noindex/zybooksLab4.build/Debug/zybooksLab4.build/Objects-normal/x86_64/main.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
If main.cpp and ItemToPurchase.cpp are compiled apart, then definition of setName method is duplicated, because first definition is in main.cpp (line #include "ItemToPurchase.cpp" included content of source file where definition of setName is) and the second definition is in ItemToPurchase.cpp . So to resolve this you should remove #include "ItemToPurchase.cpp" from main.cpp file.
Second problem, you cannot define variables in header file, look at definition of ItemToPurchase class
class ItemToPurchase {
public:
//...
} items; // you have defined items variables in header
you should delete items.

import function from .so

I need to import a function from a Linux .so library with boost.dll library. My code is like this:
namespace n1 {
namespace n2 {
struct st {
std::string n;
int m;
}
}
}
void foo(std::string const&, n1::n2::st& attr) {
/*some implementation*/
}
Here I try to import the function foo():
int main(int argc, char** argv) {
boost::filesystem::path path("some path");
boost::dll::experimental::smart_library lib(path);
auto f2 = lib.get_function<void(std::string const&, n1::n2::st&)>(path, "n1::n2::foo"); //<<----here runtime error
f2( std::string(), st{});
}
but I get this runtime error:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl >'
what(): boost::dll::shared_library::get() failed (dlerror system message: /path_to_my_library.so: undefined symbol: n1::n2::foo): Illegal seek
Because n1::n2::foo is not a C-compatible export name, I'd suggest you need either to use the mangled name, or use mangled_import
Caution: This feature is experimental
On my compiler
foo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, n1::n2::st&)
mangles to
_Z3fooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN2n12n22stE
On the topic of also importing the struct, see Class Imports
UPDATE
A working sample based on the manual mangling approach:
shared.cpp
#include "shared.h"
#include <iostream>
void foo(std::string const& msg, n1::n2::st& attr) {
std::cout << msg << " from " << __FILE__ << ":" << __LINE__ << " (" << __PRETTY_FUNCTION__ << ")\n";
std::cout << "attr.m = " << attr.m << "\n";
std::cout << "attr.n = " << attr.n << "\n";
}
shared.h
#include <string>
namespace n1 { namespace n2 { struct st { std::string n; int m; }; } }
main.cpp
#include <boost/dll.hpp>
#include <boost/dll/smart_library.hpp>
#include <boost/dll/import_mangled.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <iostream>
#include "shared.h"
int main() {
boost::filesystem::path path("./libshared.so");
try {
boost::dll::experimental::smart_library lib(path);
//auto f1 = boost::dll::experimental::import_mangled<void(std::string const&, n1::n2::st&)>(path, "foo");
auto f1 = boost::dll::import<void(std::string const&, n1::n2::st&)>(path, "_Z3fooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN2n12n22stE");
n1::n2::st arg { "world", 42 };
f1("hello", arg);
} catch(boost::exception const& e) {
std::cout << boost::diagnostic_information(e, true) << '\n';
}
}
See it Live On Coliru
Compiled with:
g++ -std=c++14 -shared -fPIC shared.cpp -o libshared.so
g++ -std=c++14 main.cpp -ldl -lboost_system -lboost_filesystem
Show the mangled names with
nm libshared.so
Run the demo with
./a.out
Prints
hello from shared.cpp:5 (void foo(const string&, n1::n2::st&))
attr.m = 42
attr.n = world

Splitting up classes c++

I'm facing a problem for the past couple of days.
First of all, I had a project that I've done. But now I've to split it's classes.
Here's how I split the classes (a class as an example):
Header file:
#ifndef QUESTION_H
#define QUESTION_H
#include <string>
#include <iostream>
#include <fstream>
#include "Answer.h"
using namespace std;
// Name -- hold a first and last name
class Question {
protected:
string type; // Type of the question, e.g MC or TF
string text; // Text of the question
public:
// Default constructor
Question ();
// Getters and setters
string getType();
string getText();
void setType (string t);
void setText (string t);
// displayText -- Display the text of the question, unformatted at present
void displayText();
// Template pattern -- algorithm in parent which does its work calling child methods
virtual void displayAnswers();
virtual void display ();
// Virtual pure functions that must be implemented by each derived class
virtual int grade (Answer*); // grade a given answer
virtual Answer* readAnswer(istream &); // read a user's answer
};
#endif
Alright, now here is the implementation:
#include "Question.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
Question::Question () { type = ""; text = ""; }
// Getters and setters
string Question::getType() { return type; }
string Question::getText() { return text; }
void Question::setType (string t) { type = t; }
void Question::setText (string t) { text = t; }
// displayText -- Display the text of the question, unformatted at present
void Question::displayText() {
cout << text;
}
// Template pattern -- algorithm in parent which does its work calling child methods
void Question::displayAnswers(){ }// Require derived classes to implement
void Question::display () {
Question::displayText();
Question::displayAnswers(); // Call derived class's displayAnswers
}
// Virtual pure functions that must be implemented by each derived class
int Question::grade (Answer*){ return 0; } // grade a given answer
Answer* Question::readAnswer(istream &){ return 0; } // read a user's answer
Ok, so I've done the other classes the same exact way.
Now what's left is the MakeFile, here it is:
project: Question MCQuestion TFQuestion Answer IntAnswer CharAnswer Main
g++ -std=c++11 Question MCQuestion TFQuestion Answer IntAnswer CharAnswer Main -o project
.cc.o:
g++ -std=c++11 -c <−o#
Now when I try running make it brings up this message:
g++ Question.cpp -o Question
/usr/lib/gcc/i586-suse-linux/4.7/../../../crt1.o: In function `_start':
/home/abuild/rpmbuild/BUILD/glibc-2.17/csu/../sysdeps/i386/start.S:113: undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [Question] Error 1
Can somebody explains it? or what am I doing wrong?
Thanks.
Edited:
Main.cc :
#include <iostream>
#include <fstream>
#include <string>
#include "Question.h"
#include "MCQuestion.h"
#include "TFQuestion.h"
#include "Answer.h"
#include "IntAnswer.h"
#include "CharAnswer.h"
#include <vector>
using namespace std;
int main () {
vector<Question *> questions; // Holds pointers to all the questions
ifstream infile ("questions.txt"); // Open the input file
int totalCorrect = 0; // Initialize the count from number of correct answers
// Read each question and place it into the questions vector
string questionType;
while ( getline (infile, questionType) ) {
if (questionType == "MC") {
MCQuestion *mc = new MCQuestion();
mc->read(infile);
questions.push_back(mc);
}
else if ( questionType[0] == 'T' or questionType[0] == 'F' ) {
TFQuestion* tf = new TFQuestion();
tf->read(infile);
tf->setAnswer(questionType[0]);
questions.push_back(tf);
}
else {
cout << "Input file is corrupt. Expected to find MC, T or F; found \"" << questionType << "\" instead." << endl;
}
}
infile.close();
// Pose each question, read and grade answers, tally total
int questionNo = 0;
for (auto &question: questions) {
// Pose the question
questionNo++; cout << questionNo << ". ";
question->display();
// Get the user's answer
Answer* ans = question->readAnswer(cin);
// Grade it and increment total
int correct = question->grade(ans);
totalCorrect = totalCorrect + correct
// Inform the user as to whether or not they got the question correct
cout << "Your answer was " << (correct?"":"not ") << "correct\n" << endl;
}
// Print the overall score
cout << "Your overall score is " << totalCorrect << "/"
<< questions.size() << endl;
return 0;
}
You create Makefile with lot of mistakes:
Should be something like this:
project: Question.o
g++ -std=c++11 $^ -o $#
.cc.o:
g++ -std=c++11 -c $< -o $#
add other dependencies into project in similar way, not forget defining main function in some of your .cc files.

Calling function by its name as string [duplicate]

I wonder if there is a simple way to call a function from a string. I know a simple way, using 'if' and 'else'.
int function_1(int i, int j) {
return i*j;
}
int function_2(int i, int j) {
return i/j;
}
...
...
...
int function_N(int i, int j) {
return i+j;
}
int main(int argc, char* argv[]) {
int i = 4, j = 2;
string function = "function_2";
cout << callFunction(i, j, function) << endl;
return 0;
}
This is the basic approach
int callFunction(int i, int j, string function) {
if(function == "function_1") {
return function_1(i, j);
} else if(function == "function_2") {
return function_2(i, j);
} else if(...) {
} ...
...
...
...
return function_1(i, j);
}
Is there something simpler?
/* New Approach */
int callFunction(int i, int j, string function) {
/* I need something simple */
return function(i, j);
}
What you have described is called reflection and C++ doesn't support it. However you might come with some work-around, for example in this very concrete case you might use an std::map that would map names of functions (std::string objects) to function pointers, which in case of functions with the very same prototype could be easier than it might seem:
#include <iostream>
#include <map>
int add(int i, int j) { return i+j; }
int sub(int i, int j) { return i-j; }
typedef int (*FnPtr)(int, int);
int main() {
// initialization:
std::map<std::string, FnPtr> myMap;
myMap["add"] = add;
myMap["sub"] = sub;
// usage:
std::string s("add");
int res = myMap[s](2,3);
std::cout << res;
}
Note that myMap[s](2,3) retrieves the function pointer mapped to string s and invokes this function, passing 2 and 3 to it, making the output of this example to be 5
Using a map of standard string to standard functions.
#include <functional>
#include <map>
#include <string>
#include <iostream>
int add(int x, int y) {return x+y;}
int sub(int x, int y) {return x-y;}
int main()
{
std::map<std::string, std::function<int(int,int)>> funcMap =
{{ "add", add},
{ "sub", sub}
};
std::cout << funcMap["add"](2,3) << "\n";
std::cout << funcMap["sub"](5,2) << "\n";
}
Even better with Lambda:
#include <functional>
#include <map>
#include <string>
#include <iostream>
int main()
{
std::map<std::string, std::function<int(int,int)>> funcMap =
{{ "add", [](int x, int y){return x+y;}},
{ "sub", [](int x, int y){return x-y;}}
};
std::cout << funcMap["add"](2,3) << "\n";
std::cout << funcMap["sub"](5,2) << "\n";
}
You can also put your functions into a shared library. You will load such library dynamically with dlopen() and then just make the calls to the functions with a std::string. Here an example:
hello.cpp
#include <iostream>
extern "C" void hello() {
std::cout << "hello" << '\n';
}
main.cpp
#include <iostream>
#include <dlfcn.h>
int main() {
using std::cout;
using std::cerr;
cout << "C++ dlopen demo\n\n";
// open the library
cout << "Opening hello.so...\n";
void* handle = dlopen("./hello.so", RTLD_LAZY);
if (!handle) {
cerr << "Cannot open library: " << dlerror() << '\n';
return 1;
}
// load the symbol
cout << "Loading symbol hello...\n";
typedef void (*hello_t)();
// reset errors
dlerror();
std::string yourfunc("hello"); // Here is your function
hello_t hello = (hello_t) dlsym(handle, yourfunc.c_str());
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol 'hello': " << dlsym_error <<
'\n';
dlclose(handle);
return 1;
}
// use it to do the calculation
cout << "Calling hello...\n";
hello();
// close the library
cout << "Closing library...\n";
dlclose(handle);
}
compilation:
g++ -fPIC -shared hello.cpp -o hello.so
and:
g++ main.cpp -o main -ldl
run:
C++ dlopen demo
Opening hello.so...
Loading symbol hello...
Calling hello...
hello
Closing library...
The example was stolen from here. There you can find more detailed explanation on dlopen() and c++
There is another possibility which hasn't been mentioned yet, which is true reflection.
An option for this is accessing functions exported from an executable or a shared library using operating system functions for resolving names to addresses. This has interesting uses like loading two 'contestant' dlls into an 'umpire' program, so that people can slug it out by having their actual codes fight each other (playing Reversi or Quake, whatever).
Another option is accessing the debug information created by the compiler. Under Windows this can be surprisingly easy for compilers that are compatible, since all the work can be off-loaded to system dlls or free dlls downloadable from Microsoft. Part of the functionality is already contained in the Windows API.
However, that falls more into the category of Systems Programming - regardless of language - and thus it pertains to C++ only insofar as it is the Systems Programming language par excellence.