Hi,
What I do in my current project:
1- I've developed a library by using C++ (compiler: arm-none-eabi-g++ -std=c++17) and generated a static library (arm-none-eabi-ar) with some c-api wrapper functions. In the static library there are some global instances of some classes, and exposed c functions provide access to their functionality
2- I've developed the app (compiler: arm-none-eabi-gcc) to be run on an ARM chip and linked with the static library. In the main function, a call is made to an init function which is in the static library
My observation is that, if I am not wrong, OOP inheritance rules don't work on those global objects. If I take a global object into a member function as a local variable, then I can access it via a pointer of its base class. A sample code is below:
Some test classes:
class CtBase { public: virtual void foo(void) = 0; int i = 0; }; class CtDer : public CtBase { public: void foo(void) override; }; void CtDer::foo(void) { ++this->i; }
Use them in a class member function implementation, where its instance (PlatformDevice) is a global object in the static library:
Version 1 - Doesn't work
CtDer der; namespace mevoo::loni6 { void PlatformDevice::init(UdpComm *udp, BufferBase *b) { CtBase *ctptr = &der; ctptr->foo(); // doesn't work // some more code
Version 2 - works:
namespace mevoo::loni6 { void PlatformDevice::init(UdpComm *udp, BufferBase *b) { CtDer der; // now a local var CtBase *ctptr = &der; ctptr->foo(); // works // some more code
Any comment would be highly appreciated.
Best regards,
Ozan
Update: I am sorry, I think it is not about OOP rules. Any pointer, no matter the type, to a global instance seems not to work. Please see the example:
CtDer der; namespace mevoo::loni6 { void PlatformDevice::init(UdpComm *udp, BufferBase *b) { CtDer *ctptr = &der; // CtBase *ctptr = &der; ctptr->foo(); // doesn't work // more code
Don't you think this is very odd? Or am I doing something wrong? I am out of any logical answer. It (CtDer* ctptr) is simply a pointer of the same type, but a call to member function causes the app crash.
Another observation.
I repeated the same test with a very simple client code to eliminate any other possibilities:
class CtClient { public: void call(CtBase *); }; void CtClient::call(CtBase *b) { // case1 b->foo(); // THIS CRASHES // case 2 // The following is ok // CtDer der; // b=&der; // b->foo(); }
API implementation:
// globals static CtDer pl_der; static CtClient pl_client; void ct_InitDevice(void) { pl_client.call(&pl_der); }
Mixing C++ and C is a little trickier than you've accounted for. Using the C linker to combine the whole thing can easily fail to handle C++ initialization mechanisms correctly. It's therefore usually better to use the C++ linker to link such chimeras.
I would agree, but for my case I am constrained to do like that since I am using 3rd party code infrastructure. I found a good article here from a good fellow. I am now trying his suggestions. If you have any such experience I would appreciate if you could share. Thank you.
ozan said: I am using 3rd party code infrastructure
That seems to contradict your earlier problem statement
ozan said:I've developed a library by
Sorry, both :) I have to use a 3rd-party lib (with C). This lib manages the whole boot sequence, rtos, and hal. I had developed another library which provides an app layer (with C++). The 3rd-party lib provides an API where I can integrate my app. I didn't mention about the whole story to set a better focus on the problem.
That's using the terms "lib" and "app" rather contrary to their actual roles. What you actually have there is a C framework which you're trying to fill out with code from a C++ lib (and a C shimmy around that). And that's a known road to hell.
C++ code generally needs the C++ version of the compiler's run-time environment and run-time library to work properly, even if you don't use all of C++'s features. To get that, the linker has to be in C++ mode, and often the main() function has to be compiled C++, too.
Thank you, Broeker, for your explanation. I figured out a nice architectural workaround to this problem, where both C and C++ 'libraries and frameworks' can live together without going to hell. It was a good experience for me and I will write an article about it and share here, so you can comment ;)