简体   繁体   中英

using C++ with namespace in C

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

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.

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 of 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

You have to set the scope for your ABC class. So replace all the ABC class as my::ABC except in the class declaration.

  extern "C" {

  CABC* create_abc() {
       my::ABC* abc = new my::ABC();
       return (my::ABC*)abc;
  }

  void call_abc_methods(const CABC *p_abc) {
     my::ABC* abc = (my::ABC*)p_abc;
     abc->doSomething();
  }

  void destroy_abc(CABC *p_abc) {
      my::ABC* abc = (my::ABC*)p_abc;
      delete abc;
  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM