I have a C++ application with the following 3 files:
// sample.h
#ifndef sample_h
#define sample_h
#include <stdio.h>
namespace mynamespace {
class sample {
public:
void myprintf(const char* tmp);
};
}
#endif
// sample.cpp
#include "sample.h"
void mynamespace::sample::myprintf(const char* val) {
printf(val);
}
// main.cpp
#include "sample.h"
int main() {
mynamespace::sample sample1; // How to omit this line?
sample1.myprintf("Hello world!");
}
Is it possible to remove the instantiation of sample1 object from main.cpp, and to have it already available (coming from the static library "sample.obj")?
If I move that line to sample.h, then the error I get during compilation is:
"class mynamespace::sample sample1" already defined in sample.obj
If I move that line to sample.cpp, then the error message is:
'sample1': undeclared identifier
Actually I understand why both errors occur, I just don't know what is the solution.
Thanks
Use static declaration:
in sample.h
namespace mynamespace{
class sample {
public:
static sample sample1;
void myprintf(const char* tmp);
};
static sample& sample1 = sample::sample1;
}
then in sample.cpp
mynamespace::sample mynamespace::sample::sample1;
from main.cpp
access the variable
mynamespace::sample::sample1.myprintf("");
mynamespace::sample1.myprintf("");
Specify an extern storage class in the header file:
namespace mynamespace {
// ...
extern sample sample1;
}
And then define it normally in sample.cpp:
mynamespace::sample sample1;
It's possible that on some compilers/operating systems it will be necessary to specify something else, something that's compiler-specific, in order to get external linkage to a data symbol in a library. This is beyond the scope of the C++ standard. Consult your compiler's documentation for more information.
Related
I've got two files, list.cpp and Header.h. Segments of the files are below. I know that if the header file is for a class, it is setup different. E.g.
class MyClass
{
public:
void foo();
int bar;
};
However, since I'm not really working with a class here (correct me if I'm wrong), am I not able to declare things under public: and private like below?
Also, if I were to place the global variable rescan in the header file as a member variable, below the function definitions, only the main function can see the variable. Why is it not within the scope of the other functions?
list.cpp:
#include <boost/algorithm/string.hpp>
#include <vector>
using namespace std;
vector<int> results;
bool rescan;
int main()
{
vector<vector<string>> list;
int success = readFile(list);
vector<vector<string>> bad = findMe(list);
system("pause");
return 0;
}
vector<vector<string>> findMe(vector<vector<string>> find)
{
rescan = true;
}
Header.h:
#pragma once
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
#include <string>
#include <vector>
std::vector<std::vector<std::string>> findMe(std::vector<std::vector<std::string>>);
#endif
EDIT: I tried this in my header file:
public:
bool rescan;
But I got "syntax error: 'public'
If you want your global to be visible in other translation units (TU) (other files), you have to declare them extern in those other TUs:
Header.h:
// Include guard omitted
extern bool rescan; // Declaration
file.cpp
#include "Header.h"
bool rescan = false; // Definition
// ...
file2.cpp
#include "Header.h" // To see extern bool rescan;
void foo()
{
rescan = true;
}
// ...
I have already checked StackOverflow to find the solution to my problem, but I think I might be missing something. I am trying to define a class in a header file (.h) and implement its methods in a cpp file (.cpp), but it does not work.
main.cpp:
#include <iostream>
#include "Message.h"
using namespace std;
int main()
{
Message *t = new (Message);
t->display();
return 0;
}
Message.h:
#ifndef MESSAGE_H_INCLUDED
#define MESSAGE_H_INCLUDED
class Message {
public:
void display();
};
#endif // MESSAGE_H_INCLUDED
Message.cpp:
#include "Message.h"
void Message::display() {
cout << "Hello!";
}
I don't understand why I keep getting the following error
undefined reference to 'Message::display()'
Compile this with the command g++ -std=c++11 Message.cpp main.cpp
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;
I got three .cpp files and two header files.
But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say
Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'
Below is my Data.h(previously known as 2.h at above)
#include <iostream>
#include <string>
using namespace std;
class Data
{
private:
string sType;
public:
Data();
Data(string);
void setSType(string);
string getSType();
};
Below is my data.cpp
#include "Data.h"
Data::Data()
{
sType = "";
}
Data::Data(string s)
{
sType = s;
}
void Data::setSType(string ss)
{
sType = ss;
}
string Data::getSType()
{
return sType;
}
Below is my PointD.h (previously known as 3.h)
#include <iostream>
#include <string>
#include "Data.h"
using namespace std;
class PointD
{
private:
int x
Data data1;
public:
PointD();
PointD(int,Data);
void setX(int);
void setData(Data);
int getX();
Data getData();
};
Below is my PointD.cpp
#include "PointD.h"
PointD::PointD()
{
x = 0;
}
PointD::PointD(int xOrdinate,Data dd)
{
x = xOrdinate;
data1 = dd;
}
void PointD::setXordinate(int Xordinate)
{
x = Xordinate;
}
void PointD::setData(Data dd)
{
data1 = dd;
};
int PointD::getXordinate()
{
return x;
}
Data PointD::getData()
{
return data1;
}
This is my main.cpp
#include <iostream>
#include <string>
#include "Data.h"
#include "PointD.h"
using namespace std;
int main()
{
const int MAX_NUM = 20;
Data ldata[MAX_NUM];
PointD pointd[MAX_NUM];
//more codes..
}
But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say
Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'
Can anybody let me know whats actually went wrong here..
You need to use include guards, or the easiest:
#pragma once
in your header files
See Purpose of Header guards for more background
Idea: 1.hpp
#ifndef HEADER_GUARD_H1_HPP__
#define HEADER_GUARD_H1_HPP__
// proceed to declare ClassOne
#endif // HEADER_GUARD_H1_HPP__
In each of your header files write:
#ifndef MYHEADERNAME_H
#define MYHEADERNAME_H
code goes here....
#endif
Its better like this:
#ifndef DATA_H /* Added */
#define DATA_H /* Added */
#include <iostream>
#include <string>
// using namespace std; /* Removed */
class Data
{
private:
std::string sType;
public:
Data();
Data( std::string const& ); // Prevent copy of string object.
void setSType( std::string& ); // Prevent copy of string object.
std::string const& getSType() const; // prevent copy on return
std::string& getSType(); // prevent copy on return
};
#endif /* DATA_H */
The big fix is adding ifndef,define,endif. The #include directive works as if copying and pasting the .h to that line. In your case the include from main.cpp are:
main.cpp
-> Data.h (1)
-> Point.h
-> Data.h (2)
At (2), Data.h has already been `pasted' into main.cpp at (1). The class declaration of Data, i.e. "class Data{ .... };" , appears twice. This is an error.
Adding include guards to the top and bottom of every .h are standard practice to avoid this problem. Don't think about it. Just do it.
Another change I'd suggest is to remove any "using namespace ..." lines from any .h . This breaks the purpose of namespaces, which is to place names into separate groups so that they are not ambiguous in cases where someone else wants an object or function with the same name. This is not an error in your program, but is an error waiting to happen.
For example, if we have:
xstring.h:
namespace xnames
{
class string
{
...
};
}
Foo.h
#include <xstring>
using namespace xnames;
...
test.cxx:
#include "Foo.h"
#include "Data.h" // Breaks at: Data( string ); -- std::string or xnames::string?
...
void test()
{
string x; // Breaks. // std::string or xnames::string?
}
Here the compiler no longer knows whether you mean xnames::string or std::string. This fails in test.cxx, which is fixable by being more specific:
void test()
{
std::string x;
}
However, this compilation still now breaks in Data.h. Therefore, if you provide that header file to someone, there will be cases when it is incompatible with their code and only fixable by changing your header files and removing the "using namespace ...;" lines.
Again, this is just good coding style. Don't think about it. Just do it.
Also, in my version of Data.h, I've changed the method parameters and return types to be references (with the &). This prevents the object and all of its state from being copied. Some clever-clogs will point our that the string class's is implementation prevents this by being copy-on-write. Maybe so, but in general, use references when passing or returning objects. It just better coding style. Get in the habit of doing it.
just a very small program to test how to use the namespace. I divide it into 3 files, since in large product, ns.h is the namespace interface and ns.cpp is the implementation. I cannot put all these stuff into one file.
Here is the code:
//ns.h
#ifndef MY_H
#define MY_H
namespace my
{
int a=1;
int b=0;
void test();
}
#endif
//ns.cpp
#include <iostream>
#include "ns.h"
using namespace my;
//my::a=1;
//my::b=0;
void my::test()
{
std::cout<<a<<std::endl;
}
//testns.cpp
#include <iostream>
#include "ns.h"
int main()
{
std::cout<<my::b<<std::endl;
my::test();
}
If I keep the above code, and compile will get:
testns.obj : error LNK2005: "int my::b" (?b#my##3HA) already defined in ns.obj
testns.obj : error LNK2005: "int my::a" (?a#my##3HA) already defined in ns.obj
If I comment the statement #include "ns.h" I will get undefined error.
D:\mfc\testns.cpp(5) : error C2653: 'my' : is not a class or namespace name
D:\mfc\testns.cpp(5) : error C2065: 'b' : undeclared identifier
D:\mfc\testns.cpp(6) : error C2653: 'my' : is not a class or namespace name
D:\mfc\testns.cpp(6) : error C2065: 'test' : undeclared identifier
Kindly help me if you know how to do this. Thanks a lot.
Headers are for declarations, not definitions. That's nothing to do with the namespace problem.
//ns.h
#ifndef MY_H
#define MY_H
namespace my
{
extern int a, b; // declared, not defined thanks to 'extern'.
void test();
}
#endif
//ns.cpp
#include <iostream>
#include "ns.h"
int my::a=1; // now we provide the actual definitions.
int my::b=0;
void my::test()
{
std::cout << my::a << std::endl;
}
//testns.cpp
#include <iostream>
#include "ns.h"
int main()
{
std::cout << my::b << std::endl;
my::test();
}
You've defined the two variables a and b in ns.h and then the header file is being included in two source files. This violates the one definition rule as the variables are now defined in both the translation units that are including ns.h.
What you need to do is declare variables in the header and define them in a single source file.
To fix the problem, change ns.h to
#ifndef MY_H
#define MY_H
namespace my
{
extern int a;
extern int b;
void test();
}
#endif
In ns.cpp
#include <iostream>
#include "ns.h"
using namespace my;
int my::a=1;
int my::b=0;
void my::test()
{
std::cout<<a<<std::endl;
}
It's not standard practice to define variables in a header file; they are re-defined every time you #include the header, leading to the linker errors that you are seeing.
If you need to share variables between source files (and there's very few good reasons for this), then you should declare them as extern in the header file, and then define them in one of your source files.