Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using C++ with namespace in C

Tags:

c++

c

namespaces

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

like image 542
Kilátó Avatar asked Sep 22 '13 15:09

Kilátó


People also ask

Why do we use namespace in C?

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.

How many namespaces are there in C?

In addition, C also partitions a program's identifiers into four namespaces. Identifiers in one namespace, are also considered different from identifiers in another.

Is it OK to use using namespace std?

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.

What is namespace std in C?

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.


2 Answers

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.

ABC.hpp

#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 */

ABCwrapper.h

#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 */

ABCprogram.h

#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 */

ABCuser.c

#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;
}

ABC.cpp

#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);
}

ABCwrapper.cpp

#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;
}

}

ABCmain.cpp

#include "ABCprogram.h"

int main()
{
   return c_code_function(39);
}

makefile

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
like image 139
Jonathan Leffler Avatar answered Oct 14 '22 11:10

Jonathan Leffler


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.

like image 43
pts Avatar answered Oct 14 '22 11:10

pts