How to implement a member function in a different header file? - c++

[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.

Related

Why does defining functions in header files create multiple definition errors, but not classes?

This question builds off these two stackoverflow posts:
multiple definition in header file
Multiple definition of namespace function
Here's the question: Why doesn't the multiple definition error appear for classes/structs/enums? Why does it only apply to functions or variables?
I wrote some example code in an effort to capture my confusion. There are 4 files: namespace.h, test.h, test.cpp, and main.cpp. The first file is included in both test.cpp and main.cpp, which leads to the multiple definition error if the correct lines are uncommented.
// namespace.h
#ifndef NAMESPACE_H
#define NAMESPACE_H
namespace NamespaceTest {
// 1. Function in namespace: must be declaration, not defintion
int test(); // GOOD
// int test() { // BAD
// return 5;
//}
// 2. Classes can live in header file with full implementation
// But if the function is defined outside of the struct, it causes compiler error
struct TestStruct {
int x;
int test() { return 10; } // GOOD
};
//int TestStruct::test() { // BAD
// return 10;
//}
// 3. Variables are also not spared from the multiple definition error.
//int x = 20; // BAD
// 4. But enums are perfectly safe.
enum TestEnum { ONE, TWO }; // GOOD
}
#endif
// test.h
#ifndef TEST_H
#define TEST_H
class Test {
public:
int test();
};
#endif
// test.cpp
#include "test.h"
#include "namespace.h"
int NamespaceTest::test() {
return 5;
}
int Test::test() {
return NamespaceTest::test() + 1;
}
// main.cpp
#include <iostream>
#include "namespace.h"
#include "test.h"
int main() {
std::cout << "NamespaceTest::test: " << NamespaceTest::test() << std::endl;
Test test;
std::cout << "Test::test: " <<test.test() << std::endl;
NamespaceTest::TestStruct test2;
std::cout << "NamespaceTest::TestStruct::test: " << test2.test() << std::endl;
std::cout << "NamespaceTest::x: " << NamespaceTest::TestEnum::ONE << std::endl;
}
g++ test.cpp main.cpp -o main.out && ./main.out
NamespaceTest::test: 5
Test::test: 6
NamespaceTest::TestStruct::test: 10
NamespaceTest::x: 0
After reading cppreference: inline specifier, I have a partial answer. The rules for inline stipulate that functions defined within classes are considered inline. And inline functions are permitted to have duplicate definitions provided (1) they live in separate translation units and (2) are identical. I'm paraphrasing, but that's the gist.
That explains why the functions are legal, but not why multiple definitions of the class or enum are ok. Likely a similar explanation I imagine, but it would be good to know for sure.
Generally when you compile a definition that is namespace scoped (like functions or global variables), your compiler will emit a global symbol for it. If this appears in multiple translation units, there will be a conflict during link-time since there are multiple definitions (which happen to be equivalent, but the linker can't check this).
This is part of the one definition rule: Exactly one definition of a function or variable is allowed in the entire program, in one of the translation units.
There are some exceptions to this, for example, class definitions and inline functions/variables. However, definitions must be the exact same (textually) in all the translation units they appear in. Class definitions are meant to be #included, so it makes sense to allow them to appear in multiple translation units.
If you define a member function inside the class body they are implicitly inline because otherwise you would not be able to include the class definition with the member function definition without breaking ODR. For example, these three are functionally equivalent:
struct TestStruct {
int x;
int test() { return 10; }
};
// Could have been written
struct TestStruct {
int x;
inline int test() { return 10; }
};
// Or as
struct TestStruct {
int x;
int test(); // The `inline` specifier could also be here
};
inline int TestStruct::test() { return 10; }
You can do this to your namespace scoped functions/variables too: inline int test() { return 5; } and inline int x = 20; would have compiled with no further issue.
This is implemented by the compiler emitting "specially marked" symbols for inline entities, and the linker picking one arbitrarily since they should all be the same.
The same exception to ODR also exists for templated functions / variables and enum declarations, since they are also meant to live in header files.

C++ what's the best way to make some functions inside source file private?

// 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.

why i can't call a static member variable in an static member function like this?

everyone! there is a code snippet like the below:
testcase.cpp
#include <string>
#include <iostream>
using namespace std;
class Test {
public:
static int b ;
static void test()
{
b = 3;
cout << b<<endl;
}
};
int main()
{
Test::test();
return 0;
}
when I click "build" button,the output message is
error LNK2001: unresolved external symbol "public: static int Test::b" (?b#Test##2HA)
1>B:\PROGRAMPROJECT\visual 2015 pro\testcase\testcase\x64\Debug\testcase.exe : fatal error LNK1120: 1 unresolved externals
but,when i change the code location like this:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class Test {
public:
//static int b;
static void test()
{
static int b;//only change this line
b = 3;
cout << b << endl;
}
};
int main()
{
Test::test();
return 0;
}
It does work!
I don't know why?Anybody can help me?
My IDE is vs pro 2015 + windows10.
How to solve it
Using C++17 you can inline the static variable which removes the need to define it outside the class.
static inline int i = 0; // I would also initialize it to zero, just to be sure
If you cannot use C++17 you will have to define
int Test::b = 0; // Again I would also initialize it to zero, just to be sure
outside of class Test
To the why
When you wrote
static void test()
{
static int b; // <-- definition is here
b = 3;
cout << b << endl;
}
you defined the function directly in the class (which means it is automatically marked inline). You then also have the definition of your static variable right there. If it is outside of the function scope, it is only a declaration (except if explicitly marked as inline - as shown above).
In contrast, in the other case it is outside of the function definition and hence your are missing the definition of the static variable.
class Test {
public:
static int b ; // <-- only declaration - definition is missing
static void test()
{
b = 3;
cout << b<<endl;
}
};
Fix spelled out for C++17
class Test {
public:
static inline int b = 0; // <-- now it is defined (and for safety initialized)
static void test()
{
b = 3;
cout << b<<endl;
}
};
Fix spelled out prior to C++17
#include <string>
#include <iostream>
using namespace std;
class Test {
public:
static int b; // declaration
static void test()
{
b = 3;
cout << b << endl;
}
};
int Test::b = 0; // definition
int main()
{
Test::test();
return 0;
}
The other anwers focus on solving the problem, instead of answering the "why" part.
When you define a function within class body, it is automatically considered to be inline and any number of translation units (think about C++ sources) may define them. That's the way you would normally define functions within header file - a function that's body will be included in multiple sources.
When you only declare a function within class body, but define it outside, it is not automatically marked as inline, which means that each translation unit that contains this definition will generate its own strong symbol. In this case, you usually decouple the declaration in a header file, from implementation in an associated source file, otherwise you'd get multiple symbol errors. (i.e. if you have non-inline definitions in headers, each source that include them generates those symbols and linker gets confused because it sees multiple versions of the same non-inline function coming from different sources)
Now, when you define a static member variable, unless it's inline, it also must be also associated with a translation unit. It's similar to declaring an extern global variable, that also has to be defined somewhere. In your case, you should simply add:
int Test::b;
It's more important when you decouple definition from declaration. Say, you have two files:
Test.hpp
class Test {
public:
static int b ;
static void test();
};
Test.cpp
#include "Test.hpp"
int Test::b;
void Test::test()
{
b = 3;
cout << b<<endl;
}
The symbols (in this case, the global variable Test::b and the function Test::test) are associated with the file Test.cpp and are generated exactly once. You may include Test.hpp in any number of source files and no additional symbols will be generated.
For referece, see https://en.cppreference.com/w/cpp/language/static
You've declared Test::b but you haven't defined it. Add this line to your code (outside of the Test class)
int Test::b;
you can give an initial value as well if you wish
int Test::b = 123;

Separating class with nested types into a header and source

There is a theme - Separating class code into a header and cpp file
It describes how to separate a class with variables and methods to .h and .cpp
But it's a simple one.
Say I have this in main.cpp
int main() {
class Filth {
int a, b;
void pra() { std::cout << a; }
class Frank {
int sacrifices;
void praisChinChin() { std::cout << "DARK LORD IS COMMINGGGGGG"; }
}
};
}
And how do I write THIS class (Filth) into a .h and .cpp so I dont get "undefined reference" and any other mistake?
And how exactly does it work (why I should write this exact code, what exactly does it do to my program)?
frank.cpp
#include "frank.h"
#include <iostream>
void Frank::praisChinChin() {
std::cout << "DARK LORD IS COMMINGGGGGG";
}
frank.h
#pragma once
class Frank {
int sacrifices = 0;
public:
void praisChinChin();
};
filth.cpp
#include "filth.h"
#include <iostream>
void Filth::pra() {
std::cout << a;
}
filth.h
#pragma once
class Filth {
int a = 0;
int b = 0;
void pra();
};
test.cpp
#include "frank.h"
int main() {
Frank f;
f.praisChinChin();
}
You are missing a semi colon at the end of class Frank.
It should compile after that.
To separate the class into .h and .cpp file you should make you function non local to the main function.
Header file might look like this.
class Filth
{
int a, b;
void pra();
class Frank
{
int sacrifices;
void praisChinChin();
};
};
And the cpp file
void Filth::pra()
{
std::cout << a;
}
void Filth::Frank::praisChinChin()
{
std::cout << "DARK LORD IS COMMINGGGGGG";
}
int main()
{
return 0;
}
I'm not sure about the "why should I write the exact code". But at the moment your code is not really doing anything. You need to create objects of your classes and call member functions, for it to have any real effect.

Instantiating an object in a namespace with a constructor whose defined in the same namespace. C++

While attempting to make a function object wrapper class for raw functions, I'm encountering a multiple definition error by trying to define in a namespace in a header file and declare it in the source. This works fine but when I try to instantiate a function object based on the raw function in the namespace, I get the error.
space.h
#ifndef SPACE_H
#define SPACE_H
namespace fobj{
class function_object
{
public:
function_object(double (*f)(double)) { raw_function = f; }
double operator()(double x) {return raw_function(x); }
private:
double (*raw_function)(double);
};
}
namespace fraw {
double raw(double x);
/** below is the trouble maker. When removed, the error doesn't occur. But also,
when the above is instead declared inline, the error doesn't occur either. **/
fobj:: function_object obj( raw );
}
#endif
space.cpp
#include "space.h"
double fraw:: raw(double x) { return x; }
main.cpp
#include <iostream>
#include "space.h"
int main()
{
std::cout<< fraw::raw(1.5)<<std::endl;
std::cout<< fraw::obj(2.5)<<std::endl;
return 0;
}
fobj:: function_object obj( raw ); is a definition - including the header in multiple translation units breaks the one definition rule. Declare the variable as extern and define it in a single implementation file.