1

I have created a static library for the following class, libtgbotengine.a and externed the class to be used in a different project.

tgbotengine.h

#include <tgbot/tgbot.h>
// Other headers
// ...
class TgBotEngine{
public:
    // Class constructors and functions
    // ...
    void start();
    
private:
    TgBot::Bot m_bot;
    std::vector<TgBot::BotCommand::Ptr> m_commands;
    // Other members
    // ...
}

extern TgBotEngine myTgBotEngine;

In a different project, I want to link libtgbotengine.a with the following cpp file. My goal is to not to include tgbotengine.h. Is externing myTgBotEngine help me achieve this?

project2.cpp

int main(){
    
    myTgBotEngine.start();
    
    return 0;
}
afp_2008
  • 1,940
  • 1
  • 19
  • 46
  • 1
    _"...to avoid including its header file"_, _"My goal is to not to include xxx.h"_ Why ihn? – JHBonarius May 20 '21 at 06:46
  • 2
    Where do you plan to have the definition of `myTgBotEngine`? – Yunnosch May 20 '21 at 06:48
  • 2
    How do you plan on telling the compiler of project2.cpp which operations/methods are available from `myTgBotEngine`? – Yunnosch May 20 '21 at 06:49
  • 2
    How do you expect the line `extern TgBotEngine myTgBotEngine;` to become effective while compiling project2.cpp? How should the compiler understand the used type `TgBotEngine` ? – Yunnosch May 20 '21 at 06:50
  • 2
    There is a solution for avoiding to include the header file. It is to copy the entire content of the header file into the code file which would otherwise need to include it. I assume that is however not an acceptable solution for you. But if you cannot answer my questions in previous comments then you probably are forced to either include or do that. – Yunnosch May 20 '21 at 06:53
  • Can I use a singleton and create an object of the class in `tgbotengine.cpp`, then `extern` it to be used in `project2.cpp`? – afp_2008 May 20 '21 at 06:54
  • 1
    What do you mean by "be used in project2.cpp"? Access it in any way? Call methods? If yes, then you need to tell the compiler about the type, by either including or copying. Even for only "externing" it, you need to use the type and for that explain about beforehand, i.e. include or copy... – Yunnosch May 20 '21 at 06:55
  • 1
    Different approach. Please explain more abstractly what you really want to achieve. Read up on https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Yunnosch May 20 '21 at 06:58
  • 1
    @Yunnosch there's also the solution of using modules, which in not a header file ;) – JHBonarius May 20 '21 at 06:59
  • 1
    @JHBonarius Please elaborate. I am not aware of a possibility to use something from a code file which has no declared API. Not cleanly... – Yunnosch May 20 '21 at 07:41
  • 2
    This is your third question on how to "hide" an external dependency. The [first one](https://stackoverflow.com/q/67608435/417197) was closed, the [second one](https://stackoverflow.com/q/67608577/417197) was downvoted and now you get comments that it seems like an XY problem. Maybe you should explain what you really are trying to achieve. – André May 20 '21 at 07:48
  • 1
    To answer the direct question "Is externing myTgBotEngine help me achieve this?" No. – n. m. could be an AI May 20 '21 at 08:33
  • 1
    @Yunnosch that's not what I'm saying. I'm not saying "no declared API". I'm just saying "no **header** file" as [C++20 Modules](https://en.cppreference.com/w/cpp/language/modules) kinda replace those. – JHBonarius May 20 '21 at 08:53
  • 1
    @JHBonarius Interesting, I was not aware of that. Thanks for poiting out. However, I suspect that whatever reasons OP has against "include" might also apply against "import". – Yunnosch May 20 '21 at 10:07

2 Answers2

2

IMHO: What you want to do is not possible.

The header file of your library is like a blue print for your class.

Lets extend the example of TgBotEngine:

class TgBotEngine{
public:
    // ...
    virtual void someMethod() = 0;    // for this example this is the first method
    virtual void start() = 0;         // for this example this is the second method
    virtual void anotherMethod() = 0; // for this example this is the third method
    // ...
}

Let's assume that TgBotEngine is a pure virtual class. Which the compiler does not know until you provide a header file :)

And a call to it like this:

void callBot(TgBotEngine& tge)
{
    tge.start();
}

What the compiler does to this line: tge.start(); is to call the second method of TgBotEngine which will be at index 1. Image it like this pseudo code: myTgBotEngine.[1]()

To determine the position of your method in the class you have to provide the header file.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
ccdMuro
  • 229
  • 2
  • 5
2

The upcoming modules will probably allow what you want to do. Unfortunately, they are still experimental...

The only portable way I know to fully hide the implementation details is to split your class between a public interface and a private implementation. This is common to Java developpers.

Here it would look like:

  1. The interface part:

    The header

     // Other headers
     // ...
     class TgBotEngine {
     public:
         // public functions
         // ...
         virtual void start() = 0;
         static std::unique_ptr<TgBotEngine> build(/*ctor parameters*/);
     }
    

    Source:

     #include <tgbot/tgbotimpl.h>
     #include <tgbot/tgbot.h>
    
     std::unique_ptr<TgBotEngine> TgBotEngine::build(/*ctor parameters*/) {
         return std::make_unique<TgBotEngineImpl>(/*ctor parameters*/);
     }
    
  2. The implementation part

     #include <tgbot/tgbot.h>
     // Other headers
     // ...
     class TgBotEngineImpl: public TgBotEngine {
     public:
         // Class constructors and functions
         // ...
         void start();
    
     private:
         TgBot::Bot m_bot;
         std::vector<TgBot::BotCommand::Ptr> m_commands;
         // Other members
         // ...
     }
    

You can then use it that way:

#include "tgb.h"
#include <memory>

int main() {
    std::unique_ptr<TgBotEngine> engine = TgBotEngine::build(/* ctor parameters*/);
    engine->start();
    ...
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252