I want to call a few "static" methods of a CPP class defined in a different file but I'm having linking problems. I created a test-case that recreates my problem and the code for it is below.
(I'm completely new to C++, I come from a Java background and I'm a little familiar with C.)
// CppClass.cpp
#include <iostream>
#include <pthread.h>
static pthread_t thread;
static pthread_mutex_t mutex;
static pthread_cond_t cond;
static int shutdown;
using namespace std;
class CppClass
{
public:
static void Start()
{
cout << "Testing start function." << endl;
shutdown = 0;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thread, &attr, run_thread, NULL);
}
static void Stop()
{
pthread_mutex_lock(&mutex);
shutdown = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
static void Join()
{
pthread_join(thread, NULL);
}
private:
static void *run_thread(void *pthread_args)
{
CppClass *obj = new CppClass();
pthread_mutex_lock(&mutex);
while (shutdown == 0)
{
struct timespec ts;
ts.tv_sec = time(NULL) + 3;
pthread_cond_timedwait(&cond, &mutex, &ts);
if (shutdown)
{
break;
}
obj->display();
}
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_exit(NULL);
return NULL;
}
void display()
{
cout << " Inside display() " << endl;
}
};
// main.cpp
#include <iostream>
/*
* If I remove the comment below and delete the
* the class declaration part, it works.
*/
// #include "CppClass.cpp"
using namespace std;
class CppClass
{
public:
static void Start();
static void Stop();
static void Join();
};
int main()
{
CppClass::Start();
while (1)
{
int quit;
cout << "Do you want to end?: (0 = stay, 1 = quit) ";
cin >> quit;
cout << "Input: " << quit << endl;
if (quit)
{
CppClass::Stop();
cout << "Joining CppClass..." << endl;
CppClass::Join();
break;
}
}
}
When I tried to compile, I get the following error:
$ g++ -o go main.cpp CppClass.cpp -l pthread
/tmp/cclhBttM.o(.text+0x119): In function `main':
: undefined reference to `CppClass::Start()'
/tmp/cclhBttM.o(.text+0x182): In function `main':
: undefined reference to `CppClass::Stop()'
/tmp/cclhBttM.o(.text+0x1ad): In function `main':
: undefined reference to `CppClass::Join()'
collect2: ld returned 1 exit status
But if I remove the class declaration in main.cpp and replace it with #include "CppClass.cpp", it works fine. Basically, I want to put these declarations in a separate .h file and use it. Am I missing something?
Thanks for the help.
It's obvious you come from a Java background because you haven't yet grasped the concept of header files. In Java the process of defining something is usually in one piece. You declare and define at the same time. In C/C++ it's a two-step process. Declaring something tells the compiler "something exists with this type, but I'll tell you later how it is actually implemented". Defining something is giving the compiler the actual implementation part. Header files are used mostly for declarations, .cpp files for definitions.
Header files are there to describe the "API" of classes, but not their actual code. It is possible to include code in the header, that's called header-inlining. You have inlined everything in CppClass.cpp (not good, header-inlining should be the exception), and then you declare your class in main.cpp AGAIN which is a double declaration in C++. The inlining in the class body leads to code reduplication everytime you use a method (this only sounds insane. See the C++ faq section on inlining for details.)
Including the double declaration in your code gives you a compiler error. Leaving the class code out compiles but gives you a linker error because now you only have the header-like class declaration in main.cpp. The linker sees no code that implements your class methods, that's why the errors appear. Different to Java, the C++ linker will NOT automatically search for object files it wants to use. If you use class XYZ and don't give it object code for XYZ, it will simply fail.
Please have a look at Wikipedia's header file article and Header File Include Patterns (the link is also at the bottom of the Wikipedia article and contains more examples)
In short:
For each class, generate a NewClass.h and NewClass.cpp file.
In the NewClass.h file, write:
class NewClass {
public:
NewClass();
int methodA();
int methodB();
}; <- don't forget the semicolon
In the NewClass.cpp file, write:
#include "NewClass.h"
NewClass::NewClass() {
// constructor goes here
}
int NewClass::methodA() {
// methodA goes here
return 0;
}
int NewClass::methodB() {
// methodB goes here
return 1;
}
In main.cpp, write:
#include "NewClass.h"
int main() {
NewClass nc;
// do something with nc
}
To link it all together, do a
g++ -o NewClassExe NewClass.cpp main.cpp
(just an example with gcc)
You're defining the class twice, which I'm pretty sure doesn't work.
Try something like this:
First a header CppClass.h file:
// CppClass.h
using namespace std;
class CppClass
{
public:
static void Start();
static void Stop();
static void Join();
private:
void *run_thread(void *pthread_args);
void display();
};
Then a CppClass.cpp file implementing it:
// CppClass.cpp
#include <iostream>
#include <pthread.h>
#include "CppClass.h"
using namespace std;
void CppClass::Start()
{
/* method body goes here */
}
void CppClass::Stop()
{
/* method body goes here */
}
void CppClass::Join()
{
/* method body goes here */
}
void *CppClass::run_thread(void *pthread_args)
{
/* method body goes here */
}
void CppClass::display() {
/* method body goes here */
}
Then your main file:
// main.cpp
#include "CppClass.h"
int main()
{
/* main method body here */
}
I believe the g++ call would be the same.
Basically, you can't declare the same class twice. You should declare the class in the header file, then declare the implementation in the cpp file. You could also put all the code inline in a single declaration of the class in a header file. But declaring it twice like you did won't work.
I hope that made sense...
I think you want to do something like:
g++ -c CppClass.cpp
g++ -c main.cpp
g++ -o go main.o CppClass.o
That should resolve it.
make a .h file with the class definition in it, and then #include that file into your 2 files.
Sure looks like the linker is not picking up you second source file.
Related
// myclass.h
#pragma once
void publicFunction();
//------
// myclass.cpp
#include "myclass.h"
#include <iostream>
void privateFunction() {
std::cout << "Hello world\n";
}
void publicFunction() {
privateFunction();
}
//-------
// main.cpp
#include "myclass.h"
#include <iostream>
void privateFunction() {
std::cout << "Hello main\n";
}
int main()
{
privateFunction();
}
The above program will fail to compile (privateFunction(void) already defined in myclass.obj). One way to solve this problem is by defining a namespace inside the source file:
#include "myclass.h"
#include <iostream>
namespace MyClass
{
void privateFunction();
// add a bunch other private functions here
}
void MyClass::privateFunction() {
std::cout << "Hello world\n";
}
//---
using namespace MyClass;
void publicFunction() {
privateFunction();
}
Is this the correct way to solve this problem? I feel like this might cause some problems later, but I don't know what is the correct way.
If you declare a function in a header file, it's not that private to begin with. If privateFunction is supposed to be an implementation detail, consider declaring it only in the translation unit. To this end, you have two common options.
Use an anonymous namespace in the implementation file.
namespace {
void privateFunction() {
std::cout << "Hello world\n";
}
}
This way, you can call privateFunction() from publicFunction, still guarding any usage of privateFunction from outside of the compilation unit.
Make the function static within the translation unit.
static void privateFunction() {
std::cout << "Hello world\n";
}
which has the same effect as 1.
Choosing among 1. and 2. is mostly a matter of taste. If you like to order function definitions such that called functions appear below the calling ones, go with 2., as 1. enforces function definitions at the point of their declarations.
Note that a drawback of such isolation is a reduced ability to write specific unit tests for the helper functions, as you cannot link against those from "outside".
Solution 1:
Declare the function static.
static void privateFunction() { ... }
Solution 2:
Declare the function inside an unnamed namespace.
namespace {
void privateFunction() { ... }
}
In both cases the function gets internal linkage, meaning it's visible only within the translation unit.
Another way is using class and inside the class you can use "private" and "public" to separate your functions and variables.
[UPDATE] a reproducible example
By splitting declaration and definition into different files, my toy code built without problem...
my main.cpp
#include <iostream>
#include "file0.h"
#include "file1.h"
#include "file2.h"
int main() {
test a;
double b = a.get_recipocal(2.0);
double c = a.get_sqrt(2.0);
std::cout << "b = " << b << std::endl;
std::cout << "c = " << c << std::endl;
return 0;
}
my file0.h
#ifndef TEST_MULTI_FILES_FILE0_H
#define TEST_MULTI_FILES_FILE0_H
class test {
private:
double a;
public:
double get_recipocal(int a);
double get_sqrt(int a);
};
#endif//TEST_MULTI_FILES_FILE0_H
my file1.h
#ifndef TEST_MULTI_FILES_FILE1_H
#define TEST_MULTI_FILES_FILE1_H
double test::get_recipocal(int a) {
return 1. / a;
}
#endif//TEST_MULTI_FILES_FILE1_H
my file2.h
#include <cmath>
#ifndef TEST_MULTI_FILES_FILE2_H
#define TEST_MULTI_FILES_FILE2_H
double test::get_sqrt(int a) {
return sqrt(a);
}
#endif//TEST_MULTI_FILES_FILE2_H
Built and run without problem. So it is not an obvious error in my production code
Thanks!
(below are original question)
I am new to C++ classes, here is my problem
for example, I have a class in file b0.h
class B::virtual public A {
void func1() {
some work1;
}
void func2() {
some work2;
}
...
};
Now I want to move the implementation of func2() into an other header file, say b1.h
so I did the following:
#include "path/to/b0.h"
void B::func2(){
some work2;
}
But the compiler will complain
use of undeclared identifier 'B'
void B::func2() {
^
(I also tested the following: in b0.h, I included b1.h and if I made func2() in b1.h a static function, I can call it from b0.h without problem.)
The goal is to separate members of B into two header files, each one contain one function implementation (I want to have a side-by-side comparison between func1 and func2 in different file, they are similar and very long). I feel this is a very common scenario, but I didn't find a good example. Is there an obvious mistake? Thank you!
What you want to do is quite common if you have larger classes. What you need is one header file with all the declarations, say b.h:
#include "path/to/a.h"
class B : virtual public A { // : instead of ::
void func1(); // return type, no function body
void func2(); // return type, no function body
};
Then you can split the definitions (the actual implementation) over as many source files as you wish. For example file b_func1.cpp might contain the definition for B::func1
#include "path/to/b.h"
void B::func1() { /* some code */ }
And file b_func2.cpp might contain the definition for B::func2
#include "path/to/b.h"
void B::func2() { /* some code */ }
Anyway, only in specific cases (like templates or inline functions) the definition can be in a header. It may work as long as you include every header only once, but it's still wrong, so put the definitions in a translation unit / source file.
I'm trying to implement a non-blocking serial communication in my C++ app. A thread is responsible to do serial communication, and I've written a ThreadSafeClass to exchange data between serial thread and main thread. Here is the core of my code:
main.cpp
#include "serial.hpp"
#include "tsqueue.hpp"
int main(int argc, char *argv[])
{
serial::init();
while (true)
{
fgets(s);
serial::outQueue.enqueue(std::string(s));
}
serial::shutdown();
return 0;
}
tsqueue.hpp
#include <mutex>
#include <queue>
namespace tsqueue
{
template <typename T>
class ThreadSafeQueue
{
private:
mutable std::mutex _mtx;
std::queue<T> _que;
public:
ThreadSafeQueue();
~ThreadSafeQueue();
void enqueue(const T &item);
T tryDequeue(const T &defaultValue, bool &done);
void clear();
bool isEmpty() const;
};
template <typename T>
ThreadSafeQueue<T>::ThreadSafeQueue() {}
template <typename T>
ThreadSafeQueue<T>::~ThreadSafeQueue() { clear(); }
template <typename T>
void tsqueue::ThreadSafeQueue<T>::enqueue(const T &item)
{
std::lock_guard<std::mutex> lock(_mtx);
_que.push(item);
}
template <typename T>
T tsqueue::ThreadSafeQueue<T>::tryDequeue(const T &defaultValue, bool &done)
{
std::lock_guard<std::mutex> lock(_mtx);
if (_que.empty())
{
done = false;
return defaultValue;
}
else
{
T item = _que.front();
_que.pop();
done = true;
return item;
}
}
} // namespace tsqueue
And serial declaration/definition,
serial.hpp
#include <string>
#include "tsqueue.hpp"
namespace serial
{
static tsqueue::ThreadSafeQueue<std::string> inQueue;
static tsqueue::ThreadSafeQueue<std::string> outQueue;
void init();
void shutdown();
}
serial.cpp
#include <string>
#include "serial.hpp"
#include "tsqueue.hpp"
static std::thread _thread;
void run()
{
while (true)
{
std::string str = serial::outQueue.tryDequeue(emptyStr, dequeued);
if (dequeued) { /* Do send 'str' */ }
if (terminationRequested) { break; }
// Some sleep
}
}
void serial::init()
{
serial::inQueue.clear();
serial::outQueue.clear();
_thread = std::thread(run);
}
void serial::shutdown()
{
if (_thread.joinable()) { _thread.join(); }
}
The problem is, when tryDequeue(...) is called by serial thread's run() in serial.cpp, it always sees empty outQueue. However while loop still sees outQueue in main.cpp with provided data, even at later times. I've find out that using debug tools of vscode. I'm new to C++, but experienced in other languages. What am I doing wrong in above code? Do run() and main() see different objects?
Compiler: g++ 7.3.0, Environment: Linux (Ubuntu 18.04)
Edit: If I remove static from definitions of inQueue and outQueue, I get multiple definition error by linker for both. Although I have appropriate include guards.
(Heavily edited after all the non-issues have been repaired and after I finally spotted what was the actual problem:)
The problem is that you have two completely separate instances of outQueue: One in main.o and one in serial.o (or .obj if you are on Windows). The problem is that you declare these as static in a header. That results in individual copies of this in every *.cpp/object which included this header.
Ideally outQueue would not be a global variable. Assuming it should be a global variable you can fix this like this:
serial.hpp
namespace serial
{
// This is a declaration of a global variable. It is harmless
// to include this everywhere.
extern tsqueue::ThreadSafeQueue<std::string> inQueue;
extern tsqueue::ThreadSafeQueue<std::string> outQueue;
}
serial.cpp
namespace serial
{
// This is the actual definition of the variables.
// Without this you get unresolved symbols during link time
// (but no error during compile time). If you have this in
// two *.cpp files you will get multiple definition linker
// errors (but no error at compile time). This must not be
// static because we want all other objects to see this as well.
tsqueue::ThreadSafeQueue<std::string> inQueue;
tsqueue::ThreadSafeQueue<std::string> outQueue;
}
The ThreadSafeQueue itself looks ok to me.
I have several c++ programs that are all reading a YAML configuration file in /etc/foo/config.yml. I have written a function that reads the config from the file
YAML::Node load_config();
(using the yaml-cpp library).
I would like this configuration to be loaded once, at the beginning of the main() function of my program, and then accessible everywhere as some kind of global variable.
Currently, many of my functions have extra parameters that are just values read from the configuration file. It could be avoided by having this global configuration, making my function definitions and calls much simpler and readable.
Side note: I am also using OpenMP for distributing computation, which means that the configuration must be accessible to all parallel processes.
Could someone give a tiny example of what this would look like when done the right way?
Thanks!
here's one way. It's a variation on the idea of the schwartz counter to manage a global singleton (for example, std::cout itself)
// globals.hpp
#include <istream>
struct globals_object
{
globals_object()
{
// record number of source files which instanciate a globals_object
++init_count_;
}
~globals_object()
{
// The last source file cleans up at program exit
if(--init_count_ == 0)
{
if (pimpl_)
{
delete pimpl_;
}
}
}
// internal implementation
struct impl
{
void load(std::istream& is)
{
// do loading code here
}
int get_param_a() const {
return a_;
}
int a_;
};
// (re)load global state
void load(std::istream&& is)
{
if (pimpl_) delete pimpl_;
pimpl_ = new impl;
pimpl_->load(is);
}
// public parameter accessor
int get_param_a() const {
return get_impl().get_param_a();
}
private:
static int init_count_;
static impl* pimpl_;
static impl& get_impl()
{
return *pimpl_;
}
};
// one of these per translation unit
static globals_object globals;
// globals.cpp
// note - not initialised - will be zero-initialised
// before global constructors are called
// you need one of these in a cpp file
int globals_object::init_count_;
globals_object::impl* globals_object::pimpl_;
// main file
// #include "globals.hpp"
#include <fstream>
int main()
{
globals.load(std::ifstream("settings.yml"));
}
// any other file
// #include "globals.hpp"
#include <iostream>
void foo()
{
std::cout << globals.get_param_a() << std::endl;
}
I have a dll plugin ,myDLL.cpp, which has the following code:
#include "myDLL.h"
#include "MainApp.h"
class A{
public:
// NOTE: SomeType is defined in main application code.
A(SomeType* data) : m_data{data}
void MemberFunc(){
// NOTE: do_something should access data in main application.
m_data->do_something();
}
private:
SomeType* m_data;
};
// exported function
A* createInstance(SomeType* data){
return new A(data);
}
In the main application I have:
stc::vector<int> IntArray;
class SomeType{
SomeType(){
IntArray.resize(1000);
}
void do_something(){
// manipulate IntArray's contents.
IntArray[rand() % IntArray.size()] = rand();
}
};
typedef A*(_createInstance)(SomeType*);
void main(){
// Load the Dll and get createInstance()
_createInstance createInstance = LoadMyDLL();
SomeType someType;
A* a = createInstance(&someType);
a->MemberFunc();
// Free the instance of A and unload the DLL.
UnloadMyDLL(a);
}
The dll code now can use the API of the main application, but it can't access the right data. When I put a break point at m_data->do_something(); and enter the method call, then I see that IntArray is empty. What am I doing wrong and how do I solve the problem?
I could succesfully run your example without experiencing your problem:
I assumed that in your headers there are only the class definitions and not definition of its member functions
So I buid a DLL project. But it failed producing the dll because of the missing do_something() function. Normal, because with your architecture it should be defined in the application not in the DLL ! I could solve the problem by making do_something() virtual.
Then I build the application. I first chose for simplicity and linked the application with the DLL (no loading issues). Unfortunately it didn't find either MemberFunc() nor createInstance(). I could solve this by exporting the DLL entry.
FInally I updated the application, to have a dynamic load of the library. For avoiding unnecessary hassle of having to find back MemberFunc(), I made it virtual as well.
In all the tests above, I had absolutely no problem. IntArray was always correct. In debug mode I could see it with the expected content, as soon as it entered the scope.
My conclusion, from these tests and looking at your snippet (expecially with doSomething not being virtual): your problem is probably that have defined SomeType class with functions and eventually IntArray in Main.h.
If this is the case, your DLL refers to its own copy of these elements and not as you think to those in main ! THis explains why you don't see the expected values !
Solution:
File MainApp.h:
class SomeType{
public:
SomeType();
virtual void do_something();
};
File MyDLL.h:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class A {
public:
A(SomeType* data);
virtual void MemberFunc(); // access through vtable. No need to link
private:
SomeType* m_data;
};
extern "C" { // use unmangled name for easo of use of dynamic loaded DLL
MYDLL_API A* createInstance(SomeType* data);
};
File MyDLL.cpp:
#define MYDLL_EXPORTS
#include "MainApp.h"
#include "MyDLL.h"
A::A(SomeType* data) : m_data{ data } {}
void A::MemberFunc(){ m_data->do_something(); }
extern "C" {
MYDLL_API A* cdecl createInstance(SomeType* data){ return new A(data); }
}
File main.cpp:
#include <Windows.h>
#include <iostream>
#include <vector>
#include "MainApp.h"
#include "MyDLL.h"
using namespace std;
vector<int> IntArray;
SomeType::SomeType(){
IntArray.resize(1000);
IntArray[0] = 1; IntArray[1] = 101; IntArray[2] = 10101;
}
void SomeType::do_something(){
for (int i = 0; i < 4; i++) // read
cout << IntArray[i] << endl;
IntArray[3] = 2702; // write
}
int main(int ac, char**av)
{
HINSTANCE LoadMe = LoadLibrary(L"MyDLL.dll");
if(LoadMe != 0)
cout << "DLL Library successfully loaded!\n";
else throw exception("DLL library failed to load!\n");
typedef A*(*_createInstance)(SomeType*);
_createInstance fcreateInstance = (_createInstance) GetProcAddress(LoadMe, "createInstance");
if (fcreateInstance)
cout << "DLL function found !\n";
else throw exception("Function not found in DLL!\n");
SomeType someType;
A* a = fcreateInstance(&someType);
a->MemberFunc();
cin.get();
}