0

I have a C++ header and cpp files like abc.hpp and abc.cpp which has 2 classes that is class A and class B, am trying to write a C layer containing different methods which calls the C++ layer methods, to call the C++ methods I need to create the instance of Class A and then use this instance to call C++ methods, I have created a C layer but tried different ways to create an instance of class B but it was not possible.

This is ABC.hpp

#ifndef ABC_HPP
#define ABC_HPP

namespace utils {

    using std::vector;
    using std::string;

    class  __declspec(dllexport) A
    {
        protected:
            string m_color;
            string m_type;

        public:
            A() {
                // TODO: Complete the constructor by intializing everything
                m_color = "";
                                m_type = "";
            }
            void setColor(string icolor){m_color = icolor;}
                        void setType(string itype){m_type = itype;}
                        string getColor(){return m_color;}
                        string getType() {return m_type;}   
            virtual ~A() {};
    };
    class __declspec(dllexport) B
    {
        // Member Variables
    protected:
        string file_name;
        string place_name;

    public:
       void setFilename(fname){file_name = fname;}
       void setPlaceName(pname){place_name = pname;} 
       string getFilename(){return file_name;}
       string  getplaceName() {return place_name;}
       void getRes();
       
    };
};
#endif

Similarly we have ABC.cpp

Next I create the C layer xyz_c.h

#ifndef XYZ_H
#define XYZ_H

#ifdef __cplusplus
extern "C"
{
#endif
    __declspec(dllexport) int getPlaceNames(char** oNames);

#ifdef __cplusplus
}
#endif
#endif

Next I create XYZ.cpp

#include "XYZ.h"
#include "ABC.h"

#ifdef __cplusplus
extern "C" {
#endif
  int getResults(char** oNames)
{
    //here I need to create the instance of B to Call C++ layer getRes()
}


#ifdef __cplusplus
}
#endif
5
  • 2
    What are those ways you have tried and what exactly "was not possible"? If you got errors then you should include those in the question Commented Sep 22, 2020 at 11:11
  • 1
    You can't make true C++ calls from C. You have to create an extern "C" interface in C++ that can be called from C. Commented Sep 22, 2020 at 11:36
  • @UnholySheep i have tried using this static B *B_instance = NULL; then void lazyAAA() { if (B_instance == NULL) { // B_instance = new B(); // } // } Commented Sep 22, 2020 at 13:16
  • Why do you need a "C layer" here? If you've got code in C++ then presumably you already have a C++ compiler and run-time support. You can (for the most part) use C-like programming techniques with a C++ compiler. So what's the real purpose here? Commented Sep 22, 2020 at 13:21
  • What is lazyAAA and how does it relate to the code in the question? Also what was the error this approach gave you? Please create a proper minimal reproducible example instead of giving unclear code snippets Commented Sep 22, 2020 at 13:27

2 Answers 2

1

You cannot. C++ was designed to allow it to use the whole set of C legacy code already written, but the other side is not possible... simply because when C was designed there was no C++ available, and C doesn't have constructs as C++ has to be able to link routines written in C.

This means that if you want to combine C and C++ code, the program must be linked as a C++ program (built as) and you can include every routine you want (you can compile individual modules as C modules) but you have to access them from the C++ code including a extern "C" linkage statement in the C++ code (and never the reverse)

C++ has a naming convention for methods and c++ functions that includes information in the name about the types and number of parameters to allow for overloading and to include the object instance in the parameter list. This is simply unknown for a C compiler, so you cannot easily guess the name that the linker uses for something so simple as a void f(void) function (it can be something like 1f4void (yes, starting with a digit) making it impossible to be accessed from C (as C identifiers must start with a letter or underscore). If you declare f as extern "C" f(void), then you can call it from C modules, and it can even be implemented in C (and compiled in c), and the linker will know it as _f (or f is in use today also, depending on the compiler)

You can even write the int main(int argc, char **argv) funtion as a C function, but when you link it, you will need to use the C++ linker, if you want your program to include C++ code.

Sign up to request clarification or add additional context in comments.

3 Comments

couldn't you take the c++ code and the C wrapper and create a static library that can be linked with other C code?
you can take the c++ code and the c wrappe, and create a static library, but if you want to use c++ libraries (with dynamic initializers, for example) you need to link the thing with the c++ linker (or let's say, to run the linker in c++ mode) or you will have trouble to run the constructors for the static global instances that must run before main() is called.
the linker is the same linker (ld(1)) but it must use the c++ runtime, and so, the whole program is a c++ program that is using c objects, not the reverse.
0

The proper way to do this is as follows. In your "C" interface code, you should have functions matching the c++ interface with the addition of a void* parameter. This parameter will be used to hold the instance for future usage by XYZ.

SO I would add a abc.c, with definitions as:

void setFilename(void* b, char *fname){
  ((B*)b)->setFilename(fname);
};

of course you will need to define also creator function such as:

void* CreateB(){
  return (void*)new B();
}

2 Comments

Using a void* is a pretty bad idea since it completely disables type checking. Usually you'd create some sort of "opaque pointer" so the user cannot pass a pointer to a different object by accident
I agree you can define an opaque pointer, for type safety.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.