Re: including a lib header file
Howard Gardner <hgardner@rawbw.com> writes:
Gary Wessle wrote:
Hi
is it right to have a line like
#include <path/to/header.h> for a library on my system, in my header
file and use some functions provided by this library in the
implementation file (file.cpp) inside a class with out declaring those
functions in the class declaration in the header file?
thanks
Believe it or not, this can be a complicated subject.
If you need something from the library header in order to write your
own header, then this is typical:
mystuff.h:
#include "path/to/somelib.h"
a_type_from_somelib a_function_that_i_provide();
mystuff.cpp
#include "mystuff.h"
a_type_from_somelib a_function_that_i_provide()
{
return a_function_from_somelib();
}
If you do NOT need something from the library header in order to write
your own header, but you do need something from the library in order
to write your implementations then this is typical:
mystuff.h:
void a_function_that_i_provide();
mystuff.cpp
#include "myclass.h"
#include "path/to/somelib.h"
void a_function_that_i_provide()
{
a_function_from_somelib();
}
And of course, if you don't need the library header at all, then this
is typical:
mystuff.h:
void a_function_that_i_provide();
mystuff.cpp
#include "myclass.h"
void a_function_that_i_provide()
{
}
The difference between the first and the second case is that in the
first case you expose your users to somelib.h, while in the second
case you do not. Mildly prefer not to expose them. Don't prefer it
strongly though. For example, don't go this far:
********* A STEP TOO FAR ********
mystuff.h:
// my_own_type is the same as a_type_from_somelib
// I looked that type up and made my own just to avoid
// including somelib.h
typedef int my_own_type;
my_own_type a_function_that_i_provide();
mystuff.cpp
#include "path/to/somelib.h"
#include "mystuff.h"
my_own_type a_function_that_i_provide()
{
return a_function_from_somelib();
}
********* A STEP TOO FAR ********
If you follow those rules, then you are honoring the informal rule
that all of us (c++ programmers) more or less follow: If I need
something from another header to use the stuff in your header, then
include it for me. If I don't, then don't.
There's a flaw in this approach that you should be aware of. Consider
this possibility.
somethingelse.h
typedef int a_type_from_somelib;
typedef bool stealth_type;
somelib.h
#include "path/to/somethingelse.h"
a_type_from_somelib a_function_from_somelib();
mystuff.h
#include "path/to/somelib.h"
a_type_from_somelib a_function_that_i_provide();
mystuff.cpp
#include "mystuff.h"
a_type_from_somelib a_function_that_i_provide()
{
return a_function_from_somelib();
}
void another_function()
{
stealth_type i_am_a_stealth_dependency;
}
The code in mystuff.cpp has a stealth dependency on
somethingelse.h. stealth_type is available to you in mystuff.cpp, so
the program compiles. It's an accident though: the REASON that
stealth_type is available is that a_type_from_somelib is needed.
The guy who maintaind somelib.h would be perfectly within his
(informal) rights to decide that he no longer needs to include
somethingelse.h and rewrite this way:
somelib.h
typedef int a_type_from_somelib;
a_type_from_somelib a_function_from_somelib();
If he did, mystuff.cpp wouldn't compile anymore because of the stealth
dependency. The proper way to write mystuff.cpp is:
mystuff.cpp
#include "mystuff.h"
#include "path/to/somethingelse.h"
a_type_from_somelib a_function_that_i_provide()
{
return a_function_from_somelib();
}
void another_function()
{
stealth_type i_am_no_longer_stealthed;
}
If you are fastidious enough, then you can avoid this mistake in your
own code.
Unhappily, the people who use your code (include mystuff.h) may not be
so fastidious, and they might build in a stealth dependency on
somethingelse.h. When their code blows up, of course, they will blame
you.
thank you
you did not explicitly mention whether I can place
a_function_from_somelib in the public scope of a
a_class_that_i_provide but I take it that you implied it. if so, then
why I getting this error which appear to be a linker error?
**************** start error ****************
fred@debian:~/myPrograms/common$ make
g++ -c -o read_data.o read_data.cpp
g++ -c -o read_data_test.o read_data_test.cpp
g++ -Wall -o proj read_data.o read_data_test.o -lgsl
/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../lib/libgsl.so: undefined
reference to `cblas_dsdot'
/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../lib/libgsl.so: undefined
reference to `cblas_dswap'
.... a long list of them
**************** end error ****************
for this project
**************** start read_data.h ****************
#ifndef READ_DATA_H
#define READ_DATA_H
#include <string>
#include <cstdio>
#include <gsl/gsl_matrix.h>
class read_data
{
int nRows, nCol;
std::string file_name;
void set_No_of_Rows_Cols();
gsl_matrix * m; // from gsl_matrix.h
void matrix_the_file();
public:
read_data(std::string const& fileName);
~read_data();
};
#endif
**************** end read_data.h ****************
**************** start read_data.cpp ****************
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cstdio>
#include "read_data.h"
#include <gsl/gsl_matrix.h>
using namespace std;
read_data::read_data( string const& fileName )
: file_name( fileName ), nCol(0), nRows(1) {
set_No_of_Rows_Cols();
matrix_the_file();
}
read_data::~read_data() {}
void read_data::matrix_the_file(){
// allocate memory for the matrix
// needs to be freed later using
// void gsl_matrix_free (gsl_matrix * m)
m = gsl_matrix_alloc (nRows, nCol);
FILE * f = fopen(file_name.c_str(), "rb");
gsl_matrix_fscanf (f, m);
fclose(f);
}
void read_data::set_No_of_Rows_Cols() {
ifstream in(file_name.c_str());
string line;
getline(in, line);
stringstream input( line.c_str() );
string word;
while(input >> word)
nCol++; // init'd by constructor
while (getline(in, line))
nRows++; // init'd by constructor
}
/*
std::string command = "wc -l";
std::system( ( command + " " + file_name ).c_str() );
}
*/
**************** end read_data.cpp ****************
**************** start read_data_test.cpp ****************
#include <fstream>
#include <iostream>
#include <string>
#include "read_data.h"
using namespace std;
int main() {
string f = "../../data/ZB/Jun06/20060405";
read_data data1( f ); // space delimited
}
**************** end read_data_test.cpp ****************
**************** start makefile ****************
OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
COMP = g++
proj: $(OBJS)
$(COMP) -Wall -o proj $(OBJS) -lgsl
#-Wall turns on all warnings
**************** end makefile ****************