Using Eclpse on Linux I have defined a C++ class, named ABC (ABC.hpp):
#ifndef ABC_HPP_
#define ABC_HPP_
#include <stdio.h>
// namespace my { <---- COMMENTED OUT
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
// } /* namespace my */ <---- COMMENTED OUT
#endif /* ABC_HPP_ */
and its implementation is (ABC.cpp):
#include "ABC.hpp"
// using namespace my; <---- COMMENTED OUT
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
To use this class in C programs, I have created a layer containing these methods (ABCwrapper.h):
typedef void CABC;
#ifdef __cplusplus
extern "C" {
#endif
CABC* create_abc();
void call_abc_methods(const CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
} // extern "C"
#endif
and
#include "ABC.hpp"
#include "ABCWrapper.h"
extern "C" {
CABC* create_abc() {
ABC* abc = new ABC();
return (ABC*)abc;
}
void call_abc_methods(const CABC *p_abc) {
ABC* abc = (ABC*)p_abc;
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = (ABC*)p_abc;
delete abc;
}
}
That's fine and I can use the ABC class instance. But what about the define the ABC class in a name space, let's say "my"? If I remove the comment signs from all name space lines the IDE complains saying that the "Type 'ABC' could not be resolved".
If I want to extend my C++ library I have to use name space for my classes but then I don't know how to use in wrappers. Please, help me to solve this mystery.
Thank you.
SK
Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries.
In addition, C also partitions a program's identifiers into four namespaces. Identifiers in one namespace, are also considered different from identifiers in another.
To put it as an advice: Do not use "using namespace" (std or other) at file scope in header files. It is OK to use it in implementation files.
Explanation: It is known that “std” (abbreviation for the standard) is a namespace whose members are used in the program. So the members of the “std” namespace are cout, cin, endl, etc. This namespace is present in the iostream.
Some mostly minor nitpicks about the code. You've already got the details of the solution with an active namespace, but there are various minor issues that should be addressed.
You would be better off introducing an incomplete type, typedef struct CABC CABC;
(in place of typedef void CABC;
), so that you get some type safety in the C code. This would prevent you passing a random FILE *
, for example, to the C interface functions, which using void
won't.
When you use the incomplete type, you should use reinterpret_cast<ABC *>(abc)
in the C wrapper functions instead of C-style casts. The compiler then shows up a problem with const-ness in the call_abc_methods()
function; the argument should not be const
(but the C-style cast hid the problem).
Additionally, your ABC.hpp
header shows a common (minor) mistake; it includes an extraneous header (#include <stdio.h>
) that is not needed to use the header safely. That line should only appear in the implementation file, ABC.cpp
, where the code uses the services of <stdio.h>
. Most headers should #include
only those other headers necessary to make the header usable on its own. They should not include random other headers.
Here's a complete working program — which has a lot of files. There are 3 headers:
ABC.hpp
— declaring class ABC
.ABCwrapper.h
— declaring the C interface to class ABC
.ABCprogram.h
— bilingual header declaring other functions.There is 1 C file:
ABCuser.c
— there must be some C code that needs to use the C interface to class ABC
to make the whole exercise worthwhile, and this is it.There are 3 C++ files:
ABC.cpp
— defining class ABC
.ABCwrapper.cpp
— defining the C interface to class ABC
.ABCmain.cpp
— the main program in a bilingual system should normally be written in C++.And there's a makefile
.
#ifndef ABC_HPP_INCLUDED
#define ABC_HPP_INCLUDED
namespace abc_library {
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
} /* namespace abc_library */
#endif /* ABC_HPP_INCLUDED */
#ifndef ABCWRAPPER_H_INCLUDED
#define ABCWRAPPER_H_INCLUDED
typedef struct CABC CABC; // Pointer to this ncomplete type used in C code
#ifdef __cplusplus
extern "C" {
#endif
CABC *create_abc(int val);
void call_abc_methods(CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
}
#endif
#endif /* ABCWRAPPER_H_INCLUDED */
#ifndef ABCPROGRAM_H_INCLUDED
#define ABCPROGRAM_H_INCLUDED
#if defined(__cplusplus)
extern "C" {
#endif
extern int c_code_function(int init);
#if defined(__cplusplus)
}
#endif
#endif /* ABCPROGRAM_H_INCLUDED */
#include "ABCwrapper.h"
#include "ABCprogram.h"
int c_code_function(int init)
{
CABC *abc = create_abc(init);
call_abc_methods(abc);
destroy_abc(abc);
return 0;
}
#include "ABC.hpp"
#include <stdio.h>
using namespace abc_library;
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
#include "ABC.hpp"
#include "ABCwrapper.h"
using namespace abc_library;
extern "C" {
CABC *create_abc(int val) {
ABC* abc = new ABC(val);
return reinterpret_cast<CABC*>(abc);
}
void call_abc_methods(CABC *p_abc) {
ABC *abc = reinterpret_cast<ABC *>(p_abc);
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = reinterpret_cast<ABC *>(p_abc);
delete abc;
}
}
#include "ABCprogram.h"
int main()
{
return c_code_function(39);
}
CC = gcc # /usr/bin/gcc
CXX = g++
RM_FR = rm -fr --
WFLAGS = -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition
SFLAGS = -std=c99
OFLAGS = -g -O3
UFLAGS = # Set on make command line only
OXXFLAGS = -g -O3
SXXFLAGS = -std=c++11
WXXFLAGS = -Wall -Wextra
UXXFLAGS = # Set on make command line only
LDFLAGS =
LDLIBS =
CFLAGS = ${OFLAGS} ${SFLAGS} ${WFLAGS} ${UFLAGS}
CXXFLAGS = ${OXXFLAGS} ${SXXFLAGS} ${WXXFLAGS} ${UXXFLAGS}
PROGRAM = abc
FILES.cpp = \
ABC.cpp \
ABCmain.cpp \
ABCwrapper.cpp
FILES.c = \
ABCuser.c
FILES.h = \
ABCprogram.h \
ABCwrapper.h
FILES.o = ${FILES.cpp:.cpp=.o} ${FILES.c:.c=.o}
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CXX} -o $@ ${CXXFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
clean:
${RM_FR} *.o *.dSYM core a.out
depend:
mkdep ${FILES.cpp} ${FILES.c}
# DO NOT DELETE THIS LINE or the blank line after it -- make depend uses them.
ABC.o: ABC.cpp
ABC.o: ABC.hpp
ABCmain.o: ABCmain.cpp
ABCmain.o: ABCprogram.h
ABCuser.o: ABCprogram.h
ABCuser.o: ABCuser.c
ABCuser.o: ABCwrapper.h
ABCwrapper.o: ABC.hpp
ABCwrapper.o: ABCwrapper.cpp
ABCwrapper.o: ABCwrapper.h
In ABCWrapper.cpp
, above the extern "C" {
line, add:
using my::ABC;
or
using namespace my;
john's suggestion (replace all instances of ABC
with my::ABC
in ABCWrapper.cpp
) also works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With