inline methods not available as symbols of shared library - c++

If I have a class which will be compiled to a shared object.
The class is declared in a .h file and implemented in a .cpp file.
This class contains a couple of inline methods.
If I write some program that links with this shared library and includes the .h file,
I will get undefined reference errors when linking it.
Is that because there are no symbols exported for inline methods ?
Am I understanding this correctly ?
UPDATE: some example code below
somelib.h
#ifndef __ABC_LIB_H
#define __ABC_LIB_H
#include <iostream>
class ABC {
ABC();
~ABC();
inline void not_callable_outside_library();
void callable_outside_library();
};
#endif
somelib.cpp
#include "somelib.h"
ABC::ABC() {}
ABC::~ABC() {}
void ABC::not_callable_outside_library(){ std::cout<<"not_callable_outside_library"<<std::endl; }
void ABC::callable_outside_library(){ std::cout<<"callable_outside_library"<<std::endl; }
program.cpp
#include "somelib.h"
int main() {
ABC x;
x.not_callable_outside_library();
return 0;
};
Compile somelib.cpp as a shared library( .so object) and link it program.cpp then you get the binary called program.
Now you should get an undefined reference when linking.

Inline functions must be defined in header files. Contrast what you have to the following:
somelib.h:
#ifndef ABC_LIB_H
#define ABC_LIB_H
#include <iostream>
class ABC {
ABC();
~ABC();
void not_callable_outside_library();
void callable_outside_library();
};
inline void ABC::not_callable_outside_library() {
std::cout << "not_callable_outside_library\n";
}
#endif
somelib.cpp:
#include "somelib.h"
ABC::ABC() { }
ABC::~ABC() { }
void ABC::callable_outside_library() {
std::cout << "callable_outside_library\n";
}
program.cpp:
#include "somelib.h"
int main() {
ABC x;
x.not_callable_outside_library();
}

Related

Why my inline functions have linking error?

I am learning C++ and currently testing inline functions. If I run my code now I will have linking error, but if I change
inline void Test::print40()
to
void Test::print40()
everything would be fine. Could you explain to me why I have an error and how to use inline function in this case.
// main.cpp file
#include "Test.h"
using namespace std;
int main()
{
Test obj1;
obj1.print40();
}
// Test.cpp file
#include <iostream>
#include "Test.h"
inline void Test::print40()
{
std::cout << "40";
}
// Test.h file
#pragma once
class Test
{
public:
void print40();
};
Inline function definition shall be in each compilation unit where it is ODR used.
On the other hand in your project the compilation unit main does not know that the function is an inline function. So it can not find its definition.
Move this definition from Test.cpp
#pragma once
class Test
{
public:
void print40();
};
inline void Test::print40()
{
std::cout << "40";
}
to the header Test.h.
The module Test.cpp is redundant.
As the function is very simple and short then it could be defined in the class definition as for example
class Test
{
public:
void print40()
{
std::cout << "40";
}
};
In this case it will be an inline function by default.

Define a static integer in a header with default value

How can I define an integer in a header file so that each cpp file which includes the header will have static const int id=0 while giving the ability to cpps to redefine it with other value.
I tried to used weak symbol but couldn't make it work.
If you are ok with preprocessor definitions you could do this:
// header.h
#ifndef CLASSID
#define CLASSID 0
#endif
static int id=CLASSID;
// class.cpp
#define CLASSID 1
#include "header.h"
This way a source file may override the default, but may also omit it, which is the sort of weak approach you mentioned.
Here's another solution that uses static variables:
// log.h
#ifndef LOG_H
#define LOG_H
#include <iostream>
#define SETLOGID(v) static logidsetter _logidsetter(_logid, v);
#define LOG(v) std::cout << "id: " << _logid << ": " << (v) << std::endl;
class logidsetter
{
public:
logidsetter(int &id, int val)
{
id = val;
}
};
static int _logid = 0;
#endif
// myclass.h
class myclass
{
public:
myclass();
void run(void);
};
// myclass.cpp
#include "log.h"
#include "myclass.h"
SETLOGID(42)
myclass::myclass()
{
LOG("myclass::cons");
}
void myclass::run(void)
{
LOG("myclass::run");
}
// main.cpp
#include "myclass.h"
#include "log.h"
SETLOGID(1)
int main()
{
myclass mc;
LOG("here's main");
mc.run();
}
The log header defines the static int _logid and provides the macro SETLOGID and the class idsetter. The cpp file may use SETLOGID to redefine the static value. This is done with an instantiation of the class idsetter along with the address of _logid and the desired value. The trick allows to bypass C++'s One Definition Rule.
The output looks like:
id: 42: myclass::cons
id: 1: here's main
id: 42: myclass::run

Static variable link error, C++

Consider this code.
//header.h
int x;
//otherSource.cpp
#include "header.h"
//main.cpp
#include "header.h"
...
int main()
{
}
In this case compiler erred with the message. "fatal error LNK1169: one or more multiply defined symbols found"
but when I add static before x, it compiles without errors.
And here is the second case.
//header.h
class A
{
public:
void f(){}
static int a;
};
int A::a = 0;
/otherSource.cpp
#include "header.h"
//main.cpp
#include "header.h"
...
int main()
{
}
In this case compiler again erred with multiple declaration.
Can anybody explain me the behavior we static variables in classes and in global declarations?? Thanks in advance.
The issue with the static member variable is that you have the definition occur in the header file. If you #include the file in multiple source files, you have multiple definitions of the static member variable.
To fix this, the header file should consist only of this:
#ifndef HEADER_H
#define HEADER_H
// In the header file
class A
{
public:
void f(){}
static int a;
};
#endif
The definition of the static variable a should be in one and only one module. The obvious place for this is in your main.cpp.
#include "header.h"
int A::a = 0; // defined here
int main()
{
}
Declare x as extern in header.h to tell the compiler that x will be defined somewhere else:
extern int x;
Then define x once in the source file which you think is most fitting.
For example in otherSource.cpp:
int x = some_initial_value;

Classes not accessing global objects

This is really puzzling me. For some reason I get a
"c1 not declared in this scope"
error from the compiler. I am usig Mingw with Code::Blocks. I would assume global variables are global to the program? Am I wrong? TYIA -Roland
// main.h
#include <iostream>
#include "classone.cpp"
#include "classtwo.cpp"
extern AnotherClass c2;
extern TheClass c1;
----------
// main.cpp
#include "main.h"
AnotherClass c2;
TheClass c1;
int main()
{
c1.function5();
c2.function2();
return 0;
}
----------
//classone.h
#include "main.h"
class AnotherClass {
`
public:
void function2();
void function3();
private:
int varone;
int vartwo;
};
----------
// classone.cpp
#include "classone.h"
void AnotherClass::function2() {
std::cout << "Function 2 Check\n";
}
void AnotherClass::function3() {
std::cout << "Function 3 Check";
}
----------
// classtwo.h
#include "main.h"
class TheClass {
public:
void function4();
void function5();
};
----------
// classtwo.cpp
#include "classtwo.h"
void TheClass::function4() {
c1.function2();
std::cout << "Function 2 Check\n";
}
void TheClass::function5() {
std::cout << "Function 3 Check";
}
It's quite silly to include .cpp files like that - only include headers.
Anyway, change main.h to this:
#include <iostream>
extern AnotherClass c2;
extern TheClass c1;
Add this to main.cpp:
AnotherClass c2;
TheClass c1;
Then include main.h in each file which needs it, like this:
// classtwo.cpp
#include "classtwo.h"
#include "main.h"
void TheClass::function4() {
c1.function2();
std::cout << "Function 2 Check\n";
}
void TheClass::function5() {
std::cout << "Function 3 Check";
}
Also, you need include guards if you don't have those already.
You need to include the class declarations in your .cpp files if you want to compile all the code in a single file. Inside classtwo.cpp insert #include "classtwo.h" and do the same for classone at the top of both files.
Standard practice is to separate the class code from the client code, so you should compile the classes into a library and link it to the main program.
Your main .h needs to include the .h files of the 2 classes, for it to work. You do not (and should not ) need to include the .cpp files.

'Undefined reference to Class::method()'

Recently I've been learning how to create methods within classes so that I only have to write a method once and for each of that class I instantiate I can call the one method and it will work only on the variables of the object that called it, I know how to do this when only using main.cpp and no headers however I am confused on how I should be writing this when I use a class header and cpp.
I have a sample of code similar to what I want to achieve:
#include <iostream>
using namespace::std;
class Object
{
public:
int stuff;
void manageStuff();
Object();
};
void Object::manageStuff()
{
stuff++;
}
Object::Object() : stuff(0) {}
Object object1, object2;
int main() {
for (int i = 0; i < 10; i++)
{
object1.manageStuff();
object2.manageStuff();
cout << object1.stuff << "\n";
cout << object2.stuff << "\n";
}
}
This works fine and allows me to have two instances of Object and a method that works independently for each instance, this is my current project:
main.cpp:
#include <iostream>
#include "Test.h"
using namespace std;
int main()
{
Test test;
for (int i = 0; i < 10; i++)
{
test.count(); // Here's my error "undefined reference to Test::count"
}
return 0;
}
Test.cpp
#include <iostream>
#include "Test.h"
using namespace std;
Test::Test()
{
//ctor
}
Test::~Test()
{
//dtor
}
Test.h
#include <iostream>
#ifndef TEST_H
#define TEST_H
class Test
{
public:
Test();
virtual ~Test();
void count();
int counter();
};
#endif // TEST_H
and finally TestFunctions.h
#include <iostream>
#include "Test.h"
#ifndef TESTFUNCTIONS_H_INCLUDED
#define TESTFUNCTIONS_H_INCLUDED
void Test::count()
{
Test::counter++;
std::cout << Test::counter;
}
#endif // TESTFUNCTIONS_H_INCLUDED
I'm sure that there will be something that's very obviously wrong to a more seasoned programmer and I'm about to look a bit thick but any help would be greatly appreciated
Thanks!
I would suggest getting rid of TestFunctions.h, and adding the implementation of Test::count() to Test.cpp. Currently, the TestFunctions.h header is not included anywhere, so you have no access to the definition from main.
You defined (i.e. implemented) Test::count() in a header file (TestFunctions.h), but you never included it anywhere so the code there is not compiled.
You should change it to be in a .cpp file, compile it and link it with the other source files. There's no reason why not to place it in Test.cpp.
Rename TestFunctions.h into TestFunctions.cpp, make it compiled same way as main.cpp and linked.
Alternatively, include TestFunctions.h somewhere, e.g. main.cpp